drawlib 0.1.1__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.

Files changed (52) hide show
  1. drawlib/.pylintrc +2 -0
  2. drawlib/__init__.py +33 -0
  3. drawlib/__main__.py +21 -0
  4. drawlib/apis.py +22 -0
  5. drawlib/assets/__init__.py +8 -0
  6. drawlib/assets/v0_1/__init__.py +8 -0
  7. drawlib/assets/v0_1/fonticons/__init__.py +8 -0
  8. drawlib/assets/v0_1/fonts/__init__.py +8 -0
  9. drawlib/v0_1/__init__.py +31 -0
  10. drawlib/v0_1/__main__.py +20 -0
  11. drawlib/v0_1/apis.py +127 -0
  12. drawlib/v0_1/private/__init__.py +20 -0
  13. drawlib/v0_1/private/arg_validator.py +163 -0
  14. drawlib/v0_1/private/command.py +204 -0
  15. drawlib/v0_1/private/core/__init__.py +15 -0
  16. drawlib/v0_1/private/core/colors.py +285 -0
  17. drawlib/v0_1/private/core/dimage.py +510 -0
  18. drawlib/v0_1/private/core/fonts.py +324 -0
  19. drawlib/v0_1/private/core/model.py +1082 -0
  20. drawlib/v0_1/private/core/model_validator.py +175 -0
  21. drawlib/v0_1/private/core/theme.py +1042 -0
  22. drawlib/v0_1/private/core/util.py +809 -0
  23. drawlib/v0_1/private/core_canvas/__init__.py +15 -0
  24. drawlib/v0_1/private/core_canvas/base.py +653 -0
  25. drawlib/v0_1/private/core_canvas/canvas.py +88 -0
  26. drawlib/v0_1/private/core_canvas/image.py +154 -0
  27. drawlib/v0_1/private/core_canvas/line.py +263 -0
  28. drawlib/v0_1/private/core_canvas/original_arrow.py +139 -0
  29. drawlib/v0_1/private/core_canvas/original_polygon.py +584 -0
  30. drawlib/v0_1/private/core_canvas/patches.py +547 -0
  31. drawlib/v0_1/private/core_canvas/text.py +136 -0
  32. drawlib/v0_1/private/download.py +58 -0
  33. drawlib/v0_1/private/dutil.py +28 -0
  34. drawlib/v0_1/private/icons/__init__.py +15 -0
  35. drawlib/v0_1/private/icons/phosphor.py +35275 -0
  36. drawlib/v0_1/private/icons/util.py +82 -0
  37. drawlib/v0_1/private/logging.py +38 -0
  38. drawlib/v0_1/private/settings.py +233 -0
  39. drawlib/v0_1/private/smartarts/__init__.py +15 -0
  40. drawlib/v0_1/private/smartarts/cycle.py +11 -0
  41. drawlib/v0_1/private/smartarts/dsart.py +17 -0
  42. drawlib/v0_1/private/smartarts/groups.py +20 -0
  43. drawlib/v0_1/private/smartarts/pyramid.py +18 -0
  44. drawlib/v0_1/private/smartarts/sourcecode.py +216 -0
  45. drawlib/v0_1/private/smartarts/table.py +11 -0
  46. drawlib/v0_1/private/smartarts/tree.py +18 -0
  47. drawlib/v0_1/private/tools.py +161 -0
  48. drawlib/v0_1/private/util.py +353 -0
  49. drawlib-0.1.1.dist-info/LICENSE.txt +202 -0
  50. drawlib-0.1.1.dist-info/METADATA +36 -0
  51. drawlib-0.1.1.dist-info/RECORD +52 -0
  52. drawlib-0.1.1.dist-info/WHEEL +4 -0
@@ -0,0 +1,1042 @@
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
+ """Drawlib style theme
11
+
12
+ Define style theme at class ``Theme``.
13
+ Default or choosed theme is applied if style is not provided.
14
+ Instance ``dtheme`` is provided to user to control theme.
15
+
16
+ """
17
+
18
+ import dataclasses
19
+ from typing import Optional, Dict, Tuple, Union, Literal, List
20
+ from copy import deepcopy
21
+
22
+ from drawlib.v0_1.private.util import error_handler
23
+ from drawlib.v0_1.private.core.model import (
24
+ IconStyle,
25
+ ImageStyle,
26
+ LineStyle,
27
+ LineArrowStyle,
28
+ ShapeStyle,
29
+ ShapeTextStyle,
30
+ TextStyle,
31
+ )
32
+ from drawlib.v0_1.private.core.fonts import (
33
+ FontBase,
34
+ Font,
35
+ FontSourceCode,
36
+ )
37
+ from drawlib.v0_1.private.arg_validator import ArgValidator
38
+
39
+
40
+ @dataclasses.dataclass
41
+ class _ThemeStyle:
42
+ """Helper dataclass for defining theme styles"""
43
+
44
+ # icon
45
+ icon_style: Literal["thin", "light", "regular", "bold", "fill"]
46
+ icon_color: Union[
47
+ Tuple[float, float, float],
48
+ Tuple[float, float, float, float],
49
+ ]
50
+
51
+ # line
52
+ line_style: Literal["solid", "dashed", "dotted", "dashdot"]
53
+ line_width: float
54
+ line_color: Union[
55
+ Tuple[float, float, float],
56
+ Tuple[float, float, float, float],
57
+ ]
58
+ arrowhead_style: Literal[
59
+ "->",
60
+ "<-",
61
+ "<->",
62
+ "-|>",
63
+ "<|-",
64
+ "<|-|>",
65
+ ]
66
+ arrowhead_scale: int
67
+
68
+ # shape
69
+ shape_line_style: Literal["solid", "dashed", "dotted", "dashdot"]
70
+ shape_line_width: float
71
+ shape_color: Union[
72
+ Tuple[float, float, float],
73
+ Tuple[float, float, float, float],
74
+ None,
75
+ ]
76
+ shape_line_color: Union[
77
+ Tuple[float, float, float],
78
+ Tuple[float, float, float, float],
79
+ None,
80
+ ]
81
+ shape_fill_color: Union[
82
+ Tuple[float, float, float],
83
+ Tuple[float, float, float, float],
84
+ None,
85
+ ]
86
+
87
+ # shapetext
88
+ shapetext_font: FontBase
89
+ shapetext_size: int
90
+ shapetext_color: Union[
91
+ Tuple[float, float, float],
92
+ Tuple[float, float, float, float],
93
+ ]
94
+
95
+ # text
96
+ text_font: FontBase
97
+ text_size: int
98
+ text_color: Union[
99
+ Tuple[float, float, float],
100
+ Tuple[float, float, float, float],
101
+ ]
102
+
103
+
104
+ class Theme:
105
+ """Drawlib Thema control class.
106
+
107
+ * define theme here
108
+ * provide theme access methods
109
+
110
+ """
111
+
112
+ @error_handler
113
+ def __init__(self):
114
+ self.theme_default()
115
+
116
+ #############
117
+ ### Thema ###
118
+ #############
119
+
120
+ @error_handler
121
+ def theme_initialize(self) -> None:
122
+ """Initialize theme.
123
+
124
+ This method need to be called before setting manual theme.
125
+
126
+ Returns:
127
+ None
128
+
129
+ """
130
+
131
+ self._background: Tuple[float, float, float, float] = (255, 255, 255, 1)
132
+ self._sourcecode_font: FontSourceCode = FontSourceCode.SOURCECODEPRO
133
+
134
+ # icon
135
+ self._iconstyles: Dict[str, IconStyle] = {}
136
+
137
+ # image
138
+ self._imagestyles: Dict[str, ImageStyle] = {}
139
+
140
+ # line
141
+ self._linestyles: Dict[str, LineStyle] = {}
142
+ self._linearrowstyles: Dict[str, LineArrowStyle] = {}
143
+
144
+ # shape
145
+ self._shapestyles: Dict[str, ShapeStyle] = {}
146
+ self._shapestyles_arc: Dict[str, ShapeStyle] = {}
147
+ self._shapestyles_arrow: Dict[str, ShapeStyle] = {}
148
+ self._shapestyles_circle: Dict[str, ShapeStyle] = {}
149
+ self._shapestyles_ellipse: Dict[str, ShapeStyle] = {}
150
+ self._shapestyles_polygon: Dict[str, ShapeStyle] = {}
151
+ self._shapestyles_rectangle: Dict[str, ShapeStyle] = {}
152
+ self._shapestyles_regularpolygon: Dict[str, ShapeStyle] = {}
153
+ self._shapestyles_wedge: Dict[str, ShapeStyle] = {}
154
+ self._shapetextstyles: Dict[str, ShapeTextStyle] = {}
155
+
156
+ # text
157
+ self._textstyles: Dict[str, TextStyle] = {}
158
+
159
+ @error_handler
160
+ def theme_default(self) -> None:
161
+ """Change theme to default.
162
+
163
+ Returns:
164
+ None
165
+
166
+ """
167
+
168
+ # https://coolors.co/6d7cc5-70c2bf-e4dfda-d4b483-c1666b
169
+
170
+ # primary color
171
+ blue_light = _get_rgba_from_hex("#6D7CC5")
172
+ blue_dark = _get_rgba_from_hex("#12152B")
173
+
174
+ # secondary color
175
+ green_light = _get_rgba_from_hex("#70C2BF")
176
+ green_dark = _get_rgba_from_hex("#0C1D1C")
177
+
178
+ # third color
179
+ pink_light = _get_rgba_from_hex("#C1666B")
180
+ pink_dark = _get_rgba_from_hex("#1D0C0D")
181
+
182
+ tstyle1 = _ThemeStyle(
183
+ icon_style="thin",
184
+ icon_color=blue_dark,
185
+ line_style="solid",
186
+ line_width=2,
187
+ line_color=blue_dark,
188
+ arrowhead_style="->",
189
+ arrowhead_scale=20,
190
+ shape_line_style="solid",
191
+ shape_line_width=1,
192
+ shape_line_color=blue_dark,
193
+ shape_fill_color=blue_light,
194
+ shape_color=None,
195
+ shapetext_font=Font.SANSSERIF_REGULAR,
196
+ shapetext_size=16,
197
+ shapetext_color=blue_dark,
198
+ text_font=Font.SANSSERIF_REGULAR,
199
+ text_size=16,
200
+ text_color=blue_dark,
201
+ )
202
+
203
+ tstyle2 = deepcopy(tstyle1)
204
+ tstyle2.line_color = green_dark
205
+ tstyle2.shape_line_color = green_dark
206
+ tstyle2.shape_fill_color = green_light
207
+ tstyle2.shapetext_color = green_dark
208
+ tstyle2.text_color = green_dark
209
+
210
+ tstyle3 = deepcopy(tstyle1)
211
+ tstyle3.line_color = pink_dark
212
+ tstyle3.shape_line_color = pink_dark
213
+ tstyle3.shape_fill_color = pink_light
214
+ tstyle3.shapetext_color = pink_dark
215
+ tstyle3.text_color = pink_dark
216
+
217
+ self._apply_thema_styles(
218
+ background=(255, 255, 255, 1), # white
219
+ sourcecode_font=FontSourceCode.SOURCECODEPRO,
220
+ tstyle1=tstyle1,
221
+ tstyle2=tstyle2,
222
+ tstyle3=tstyle3,
223
+ )
224
+
225
+ @error_handler
226
+ def theme_gray(self) -> None:
227
+ """Change theme to gray.
228
+
229
+ Returns:
230
+ None
231
+
232
+ """
233
+
234
+ # https://coolors.co/palette/f8f9fa-e9ecef-dee2e6-ced4da-adb5bd-6c757d-495057-343a40-212529
235
+
236
+ # primary color
237
+ gray1 = _get_rgba_from_hex("#ADB5BD")
238
+ gray_dark = _get_rgba_from_hex("#212529")
239
+
240
+ # secondary color
241
+ gray2 = _get_rgba_from_hex("#CED4DA")
242
+
243
+ # third color
244
+ gray3 = _get_rgba_from_hex("#DEE2E6")
245
+
246
+ tstyle1 = _ThemeStyle(
247
+ icon_style="thin",
248
+ icon_color=gray_dark,
249
+ line_style="solid",
250
+ line_width=2,
251
+ line_color=gray_dark,
252
+ arrowhead_style="->",
253
+ arrowhead_scale=20,
254
+ shape_line_style="solid",
255
+ shape_line_width=1,
256
+ shape_line_color=gray_dark,
257
+ shape_fill_color=gray1,
258
+ shape_color=None,
259
+ shapetext_font=Font.SANSSERIF_REGULAR,
260
+ shapetext_size=16,
261
+ shapetext_color=gray_dark,
262
+ text_font=Font.SANSSERIF_REGULAR,
263
+ text_size=16,
264
+ text_color=gray_dark,
265
+ )
266
+
267
+ tstyle2 = deepcopy(tstyle1)
268
+ tstyle2.shape_fill_color = gray2
269
+
270
+ tstyle3 = deepcopy(tstyle1)
271
+ tstyle3.shape_fill_color = gray3
272
+
273
+ self._apply_thema_styles(
274
+ background=(255, 255, 255, 1), # white
275
+ sourcecode_font=FontSourceCode.SOURCECODEPRO,
276
+ tstyle1=tstyle1,
277
+ tstyle2=tstyle2,
278
+ tstyle3=tstyle3,
279
+ )
280
+
281
+ ##################
282
+ ### Background ###
283
+ ##################
284
+
285
+ @error_handler
286
+ def background_color_get(self) -> Tuple[int, int, int]:
287
+ """Get theme background color.
288
+
289
+ Returns:
290
+ color
291
+
292
+ """
293
+
294
+ # has no alpha
295
+ if len(self._background) == 3:
296
+ return self._background
297
+
298
+ # has alpha
299
+ b = self._background
300
+ return (b[0], b[1], b[2])
301
+
302
+ @error_handler
303
+ def background_color_set(
304
+ self,
305
+ color: Union[
306
+ Tuple[int, int, int],
307
+ Tuple[int, int, int, float],
308
+ ],
309
+ ) -> None:
310
+ """Set theme background color.
311
+
312
+ Args:
313
+ color: background color. (R, G, B)
314
+
315
+ Returns:
316
+ None
317
+
318
+ """
319
+
320
+ ArgValidator.validate_color("color", color)
321
+ self._background = color
322
+
323
+ @error_handler
324
+ def background_alpha_get(self) -> float:
325
+ """Get theme background alpha.
326
+
327
+ Returns:
328
+ float: 0 ~ 1.0
329
+
330
+ """
331
+
332
+ # has no alpha
333
+ if len(self._background) == 3:
334
+ return 1.0
335
+
336
+ # has alpha
337
+ return self._background[3]
338
+
339
+ @error_handler
340
+ def background_alpha_set(self, alpha: float) -> None:
341
+ """Set theme background alpha.
342
+
343
+ Args:
344
+ alpha: float. 0.0 ~ 1.0
345
+
346
+ Returns:
347
+ None
348
+
349
+ """
350
+
351
+ ArgValidator.validate_alpha("alpha", alpha)
352
+
353
+ if len(self._background) == 3:
354
+ # tuple + tuple makes concat tuple
355
+ self._background = self._background + (alpha,)
356
+ return
357
+
358
+ self._background = self._background[:-1] + (alpha,)
359
+
360
+ ############
361
+ ### Icon ###
362
+ ############
363
+
364
+ @error_handler
365
+ def iconstyle_get(self, name: str = "1") -> IconStyle:
366
+ """Get theme IconStyle.
367
+
368
+ Args:
369
+ name(option): key
370
+
371
+ Returns:
372
+ IconStyle
373
+
374
+ """
375
+
376
+ return deepcopy(self._iconstyles[name])
377
+
378
+ @error_handler
379
+ def iconstyle_set(self, style: IconStyle, name: str = "1") -> None:
380
+ """Set theme IconStyle.
381
+
382
+ Args:
383
+ style: theme IconStyle
384
+ name(optional): key
385
+
386
+ Returns:
387
+ None
388
+
389
+ """
390
+
391
+ ArgValidator.validate_iconstyle("style", style)
392
+ ArgValidator.validate_str("name", name)
393
+ self._iconstyles[name] = deepcopy(style)
394
+
395
+ ############
396
+ ### Image ###
397
+ ############
398
+
399
+ @error_handler
400
+ def imagestyle_get(self, name: str = "1") -> ImageStyle:
401
+ """Get theme ImageStyle.
402
+
403
+ Args:
404
+ name(option): key
405
+
406
+ Returns:
407
+ ImageStyle
408
+
409
+ """
410
+
411
+ return deepcopy(self._imagestyles[name])
412
+
413
+ @error_handler
414
+ def imagestyle_set(self, style: ImageStyle, name: str = "1") -> None:
415
+ """Set theme ImageStyle.
416
+
417
+ Args:
418
+ style: theme ImageStyle
419
+ name(optional): key
420
+
421
+ Returns:
422
+ None
423
+
424
+ """
425
+
426
+ ArgValidator.validate_imagestyle("style", style)
427
+ ArgValidator.validate_str("name", name)
428
+ self._imagestyles[name] = deepcopy(style)
429
+
430
+ ############
431
+ ### Line ###
432
+ ############
433
+
434
+ @error_handler
435
+ def linestyle_get(self, name: str = "1") -> LineStyle:
436
+ """Get theme LineStyle.
437
+
438
+ Args:
439
+ name(option): key
440
+
441
+ Returns:
442
+ LineStyle
443
+
444
+ """
445
+
446
+ return deepcopy(self._linestyles[name])
447
+
448
+ @error_handler
449
+ def linestyle_set(self, style: LineStyle, name: str = "1") -> None:
450
+ """Set theme LineStyle.
451
+
452
+ Args:
453
+ style: theme LineStyle
454
+ name(optional): key
455
+
456
+ Returns:
457
+ None
458
+
459
+ """
460
+
461
+ ArgValidator.validate_linestyle("style", style)
462
+ ArgValidator.validate_str("name", name)
463
+ self._linestyles[name] = deepcopy(style)
464
+
465
+ @error_handler
466
+ def linearrowstyle_get(self, name: str = "1") -> LineArrowStyle:
467
+ """Get theme LineArrowStyle.
468
+
469
+ Args:
470
+ name(optional): key
471
+
472
+ Returns:
473
+ LineArrowStyle
474
+
475
+ """
476
+
477
+ return deepcopy(self._linearrowstyles[name])
478
+
479
+ @error_handler
480
+ def linearrowstyle_set(self, style: LineArrowStyle, name: str = "1") -> None:
481
+ """Set theme LineArrowStyle.
482
+
483
+ Args:
484
+ style: theme LineArrowStyle
485
+ name(optional): key
486
+
487
+ Returns:
488
+ None
489
+
490
+ """
491
+
492
+ ArgValidator.validate_linearrowstyle("style", style)
493
+ ArgValidator.validate_str("name", name)
494
+ self._linearrowstyles[name] = deepcopy(style)
495
+
496
+ ############
497
+ ### Text ###
498
+ ############
499
+
500
+ @error_handler
501
+ def textstyle_get(self, name: str = "1") -> TextStyle:
502
+ """Get theme TextStyle.
503
+
504
+ Args:
505
+ name(optional): key
506
+
507
+ Returns:
508
+ TextStyle
509
+
510
+ """
511
+
512
+ return deepcopy(self._textstyles[name])
513
+
514
+ @error_handler
515
+ def textstyle_set(self, style: TextStyle, name: str = "1") -> None:
516
+ """Set theme TextStyle.
517
+
518
+ Args:
519
+ style: theme TextStyle
520
+ name(optional): key
521
+
522
+ Returns:
523
+ None
524
+
525
+ """
526
+
527
+ ArgValidator.validate_textstyle("style", style)
528
+ ArgValidator.validate_str("name", name)
529
+ self._textstyles[name] = deepcopy(style)
530
+
531
+ @error_handler
532
+ def sourcecodefont_get(self) -> FontSourceCode:
533
+ """Get theme FontSourceCode.
534
+
535
+ Returns:
536
+ FontSourceCode
537
+
538
+ """
539
+ return self._sourcecode_font
540
+
541
+ @error_handler
542
+ def sourcecodefont_set(self, font: FontSourceCode) -> None:
543
+ """Set theme FontSourceCode.
544
+
545
+ Args:
546
+ font: FontSourceCode
547
+
548
+ Returns:
549
+ None
550
+
551
+ """
552
+ ArgValidator.validate_fontsourcecode(font)
553
+ self._sourcecode_font = font
554
+
555
+ #############
556
+ ### Shape ###
557
+ #############
558
+
559
+ @error_handler
560
+ def shapestyle_get(self, name: str = "1") -> ShapeStyle:
561
+ """Get theme ShapeStyle.
562
+
563
+ Args:
564
+ name(optional): key
565
+
566
+ Returns:
567
+ ShapeStyle
568
+
569
+ """
570
+
571
+ return deepcopy(self._shapestyles[name])
572
+
573
+ @error_handler
574
+ def shapestyle_set(self, style: ShapeStyle, name: str = "1") -> None:
575
+ """Set theme ShapeStyle.
576
+
577
+ Args:
578
+ style: theme ShapeStyle
579
+ name(optional): key
580
+
581
+ Returns:
582
+ None
583
+
584
+ """
585
+
586
+ ArgValidator.validate_shapestyle("style", style)
587
+ ArgValidator.validate_str("name", name)
588
+ self._shapestyles[name] = deepcopy(style)
589
+
590
+ @error_handler
591
+ def shapetextstyle_get(self, name: str = "1") -> ShapeTextStyle:
592
+ """Get theme ShapeTextStyle.
593
+
594
+ Args:
595
+ name(optional): key
596
+
597
+ Returns:
598
+ ShapeTextStyle
599
+
600
+ """
601
+
602
+ return deepcopy(self._shapetextstyles[name])
603
+
604
+ @error_handler
605
+ def shapetextstyle_set(self, style: ShapeTextStyle, name: str = "1") -> None:
606
+ """Set theme ShapeTextStyle.
607
+
608
+ Args:
609
+ style: theme ShapeTextStyle
610
+ name(optional): key
611
+
612
+ Returns:
613
+ None
614
+
615
+ """
616
+
617
+ ArgValidator.validate_shapetextstyle("style", style)
618
+ ArgValidator.validate_str("name", name)
619
+ self._shapetextstyles[name] = deepcopy(style)
620
+
621
+ @error_handler
622
+ def shapestyle_arc_get(self, name: str = "1") -> ShapeStyle:
623
+ """Get theme ShapeStyle for arc.
624
+
625
+ If ShapeStyle is not set for arc, get general ShapeStyle.
626
+
627
+ Args:
628
+ name(optional): key
629
+
630
+ Returns:
631
+ ShapeStyle
632
+
633
+ """
634
+
635
+ if name in self._shapestyles_arc:
636
+ return deepcopy(self._shapestyles_arc[name])
637
+ style = deepcopy(self._shapestyles[name])
638
+ style.fcolor = None # arc default style doesn't have fill color
639
+ return style
640
+
641
+ @error_handler
642
+ def shapestyle_arc_set(self, style: ShapeStyle, name: str = "1") -> None:
643
+ """Set theme ShapeStyle for arc.
644
+
645
+ Args:
646
+ style: theme ShapeStyle for arc
647
+ name(optional): key
648
+
649
+ Returns:
650
+ None
651
+
652
+ """
653
+
654
+ ArgValidator.validate_shapestyle("style", style)
655
+ ArgValidator.validate_str("name", name)
656
+ self._shapestyles_arc[name] = deepcopy(style)
657
+
658
+ @error_handler
659
+ def shapestyle_arrow_get(self, name: str = "1") -> ShapeStyle:
660
+ """Get theme ShapeStyle for arrow.
661
+
662
+ If ShapeStyle is not set for arrow, get general ShapeStyle.
663
+
664
+ Args:
665
+ name(optional): key
666
+
667
+ Returns:
668
+ ShapeStyle
669
+
670
+ """
671
+
672
+ if name in self._shapestyles_arrow:
673
+ return deepcopy(self._shapestyles_arrow[name])
674
+ return deepcopy(self._shapestyles[name])
675
+
676
+ @error_handler
677
+ def shapestyle_arrow_set(self, style: ShapeStyle, name: str = "1") -> None:
678
+ """Set theme ShapeStyle for arrow.
679
+
680
+ Args:
681
+ style: theme ShapeStyle for arrow
682
+ name(optional): key
683
+
684
+ Returns:
685
+ None
686
+
687
+ """
688
+
689
+ ArgValidator.validate_shapestyle("style", style)
690
+ ArgValidator.validate_str("name", name)
691
+ self._shapestyles_arrow[name] = deepcopy(style)
692
+
693
+ @error_handler
694
+ def shapestyle_circle_get(self, name: str = "1") -> ShapeStyle:
695
+ """Get theme ShapeStyle for circle.
696
+
697
+ If ShapeStyle is not set for circle, get general ShapeStyle.
698
+
699
+ Args:
700
+ name(optional): key
701
+
702
+ Returns:
703
+ ShapeStyle
704
+
705
+ """
706
+
707
+ if name in self._shapestyles_circle:
708
+ return deepcopy(self._shapestyles_circle[name])
709
+ return deepcopy(self._shapestyles[name])
710
+
711
+ @error_handler
712
+ def shapestyle_circle_set(self, style: ShapeStyle, name: str = "1") -> None:
713
+ """Set theme ShapeStyle for circle.
714
+
715
+ Args:
716
+ style: theme ShapeStyle for circle
717
+ name(optional): key
718
+
719
+ Returns:
720
+ None
721
+
722
+ """
723
+ ArgValidator.validate_shapestyle("style", style)
724
+ ArgValidator.validate_str("name", name)
725
+ self._shapestyles_circle[name] = deepcopy(style)
726
+
727
+ @error_handler
728
+ def shapestyle_ellipse_get(self, name: str = "1") -> ShapeStyle:
729
+ """Get theme ShapeStyle for ellipse.
730
+
731
+ If ShapeStyle is not set for ellipse, get general ShapeStyle.
732
+
733
+ Args:
734
+ name(optional): key
735
+
736
+ Returns:
737
+ ShapeStyle
738
+
739
+ """
740
+
741
+ if name in self._shapestyles_ellipse:
742
+ return deepcopy(self._shapestyles_ellipse[name])
743
+ return deepcopy(self._shapestyles[name])
744
+
745
+ @error_handler
746
+ def shapestyle_ellipse_set(self, style: ShapeStyle, name: str = "1") -> None:
747
+ """Set theme ShapeStyle for ellipse.
748
+
749
+ Args:
750
+ style: theme ShapeStyle for ellipse
751
+ name(optional): key
752
+
753
+ Returns:
754
+ None
755
+
756
+ """
757
+
758
+ ArgValidator.validate_shapestyle("style", style)
759
+ ArgValidator.validate_str("name", name)
760
+ self._shapestyles_ellipse[name] = deepcopy(style)
761
+
762
+ @error_handler
763
+ def shapestyle_polygon_get(self, name: str = "1") -> ShapeStyle:
764
+ """Get theme ShapeStyle for polygon.
765
+
766
+ If ShapeStyle is not set for polygon, get general ShapeStyle.
767
+
768
+ Args:
769
+ name(optional): key
770
+
771
+ Returns:
772
+ ShapeStyle
773
+
774
+ """
775
+
776
+ if name in self._shapestyles_polygon:
777
+ return deepcopy(self._shapestyles_polygon[name])
778
+ return deepcopy(self._shapestyles[name])
779
+
780
+ @error_handler
781
+ def shapestyle_polygon_set(self, style: ShapeStyle, name: str = "1") -> None:
782
+ """Set theme ShapeStyle for polygon.
783
+
784
+ Args:
785
+ style: theme ShapeStyle for polygon
786
+ name(optional): key
787
+
788
+ Returns:
789
+ None
790
+
791
+ """
792
+
793
+ ArgValidator.validate_shapestyle("style", style)
794
+ ArgValidator.validate_str("name", name)
795
+ self._shapestyles_polygon[name] = deepcopy(style)
796
+
797
+ @error_handler
798
+ def shapestyle_rectangle_get(self, name: str = "1") -> ShapeStyle:
799
+ """Get theme ShapeStyle for rectangle.
800
+
801
+ If ShapeStyle is not set for rectangle, get general ShapeStyle.
802
+
803
+ Args:
804
+ name(optional): key
805
+
806
+ Returns:
807
+ ShapeStyle
808
+
809
+ """
810
+
811
+ if name in self._shapestyles_rectangle:
812
+ return deepcopy(self._shapestyles_rectangle[name])
813
+ return deepcopy(self._shapestyles[name])
814
+
815
+ @error_handler
816
+ def shapestyle_rectangle_set(self, style: ShapeStyle, name: str = "1") -> None:
817
+ """Set theme ShapeStyle for rectangle.
818
+
819
+ Args:
820
+ style: theme ShapeStyle for rectangle
821
+ name(optional): key
822
+
823
+ Returns:
824
+ None
825
+
826
+ """
827
+
828
+ ArgValidator.validate_shapestyle("style", style)
829
+ ArgValidator.validate_str("name", name)
830
+ self._shapestyles_rectangle[name] = deepcopy(style)
831
+
832
+ @error_handler
833
+ def shapestyle_regularpolygon_get(self, name: str = "1") -> ShapeStyle:
834
+ """Get theme ShapeStyle for regularpolygon.
835
+
836
+ If ShapeStyle is not set for regularpolygon, get general ShapeStyle.
837
+
838
+ Args:
839
+ name(optional): key
840
+
841
+ Returns:
842
+ ShapeStyle
843
+
844
+ """
845
+
846
+ if name in self._shapestyles_regularpolygon:
847
+ return deepcopy(self._shapestyles_regularpolygon[name])
848
+ return deepcopy(self._shapestyles[name])
849
+
850
+ @error_handler
851
+ def shapestyle_regularpolygon_set(self, style: ShapeStyle, name: str = "1") -> None:
852
+ """Set theme ShapeStyle for regularpolygon.
853
+
854
+ Args:
855
+ style: theme ShapeStyle for regularpolygon
856
+ name(optional): key
857
+
858
+ Returns:
859
+ None
860
+
861
+ """
862
+
863
+ ArgValidator.validate_shapestyle("style", style)
864
+ ArgValidator.validate_str("name", name)
865
+ self._shapestyles_regularpolygon[name] = deepcopy(style)
866
+
867
+ @error_handler
868
+ def shapestyle_wedge_get(self, name: str = "1") -> ShapeStyle:
869
+ """Get theme ShapeStyle for wedge.
870
+
871
+ If ShapeStyle is not set for wedge, get general ShapeStyle.
872
+
873
+ Args:
874
+ name(optional): key
875
+
876
+ Returns:
877
+ ShapeStyle
878
+
879
+ """
880
+
881
+ if name in self._shapestyles_wedge:
882
+ return deepcopy(self._shapestyles_wedge[name])
883
+ return deepcopy(self._shapestyles[name])
884
+
885
+ @error_handler
886
+ def shapestyle_wedge_set(self, style: ShapeStyle, name: str = "1") -> None:
887
+ """Set theme ShapeStyle for wedge.
888
+
889
+ Args:
890
+ style: theme ShapeStyle for wedge
891
+ name(optional): key
892
+
893
+ Returns:
894
+ None
895
+
896
+ """
897
+
898
+ ArgValidator.validate_shapestyle("style", style)
899
+ ArgValidator.validate_str("name", name)
900
+ self._shapestyles_wedge[name] = deepcopy(style)
901
+
902
+ ###############
903
+ ### Private ###
904
+ ###############
905
+
906
+ def _apply_thema_styles(
907
+ self,
908
+ background: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
909
+ sourcecode_font: FontSourceCode,
910
+ tstyle1: _ThemeStyle,
911
+ tstyle2: Optional[_ThemeStyle] = None,
912
+ tstyle3: Optional[_ThemeStyle] = None,
913
+ tstyle4: Optional[_ThemeStyle] = None,
914
+ tstyle5: Optional[_ThemeStyle] = None,
915
+ ) -> None:
916
+
917
+ self.theme_initialize()
918
+ self._background = background
919
+ self._sourcecode_font = sourcecode_font
920
+
921
+ tstyles: List[_ThemeStyle] = [
922
+ tstyle1,
923
+ tstyle2,
924
+ tstyle3,
925
+ tstyle4,
926
+ tstyle5,
927
+ ]
928
+ for i, tstyle in enumerate(tstyles, start=1):
929
+ name = str(i)
930
+ if tstyle is None:
931
+ if name == "1":
932
+ raise ValueError('default thema style "1" must be configured.')
933
+ continue
934
+
935
+ self.iconstyle_set(
936
+ style=IconStyle(
937
+ style=tstyle.icon_style,
938
+ color=tstyle.icon_color,
939
+ ),
940
+ name=name,
941
+ )
942
+ self.imagestyle_set(
943
+ style=ImageStyle(
944
+ lstyle=tstyle.shape_line_style,
945
+ lcolor=tstyle.shape_line_color,
946
+ ),
947
+ name=name,
948
+ )
949
+ self.linestyle_set(
950
+ style=LineStyle(
951
+ style=tstyle.line_style,
952
+ width=tstyle.line_width,
953
+ color=tstyle.line_color,
954
+ ),
955
+ name=name,
956
+ )
957
+
958
+ self.linearrowstyle_set(
959
+ style=LineArrowStyle(
960
+ lstyle=tstyle.line_style,
961
+ lwidth=tstyle.line_width,
962
+ hstyle=tstyle.arrowhead_style,
963
+ hscale=tstyle.arrowhead_scale,
964
+ color=tstyle.line_color,
965
+ ),
966
+ name=name,
967
+ )
968
+
969
+ self.textstyle_set(
970
+ style=TextStyle(
971
+ font=tstyle.text_font,
972
+ size=tstyle.text_size,
973
+ color=tstyle.text_color,
974
+ halign=None, # depends on situation. keep None.
975
+ valign=None, # depends on situation. keep None.
976
+ ),
977
+ name=name,
978
+ )
979
+
980
+ self.shapestyle_set(
981
+ style=ShapeStyle(
982
+ lwidth=tstyle.shape_line_width,
983
+ lstyle=tstyle.shape_line_style,
984
+ lcolor=tstyle.shape_line_color,
985
+ fcolor=tstyle.shape_fill_color,
986
+ halign=None, # depends on situation. keep None.
987
+ valign=None, # depends on situation. keep None.
988
+ ),
989
+ name=name,
990
+ )
991
+
992
+ self.shapetextstyle_set(
993
+ style=ShapeTextStyle(
994
+ font=tstyle.text_font,
995
+ size=tstyle.text_size,
996
+ color=tstyle.text_color,
997
+ halign=None, # depends on situation. keep None.
998
+ valign=None, # depends on situation. keep None.
999
+ ),
1000
+ name=name,
1001
+ )
1002
+
1003
+
1004
+ def _get_rgba_from_hex(hex_color: str) -> Tuple[int, int, int, float]:
1005
+ """
1006
+ Convert a hexadecimal color code to RGBA values.
1007
+
1008
+ Args:
1009
+ hex_color (str): The hexadecimal color code (e.g., "#FF5733" or "#FFF").
1010
+
1011
+ Returns:
1012
+ tuple[int, int, int, float]: A tuple containing the RGBA values (0-255 for R, G, B and 0.0-1.0 for A).
1013
+ """
1014
+
1015
+ # Remove the '#' prefix if present
1016
+ hex_color = hex_color.lstrip("#")
1017
+
1018
+ # Determine the length of the hex color code
1019
+ hex_length = len(hex_color)
1020
+
1021
+ # Convert the hex code to RGB values
1022
+ if hex_length == 3: # Short hex format (#RGB)
1023
+ r = int(hex_color[0] * 2, 16)
1024
+ g = int(hex_color[1] * 2, 16)
1025
+ b = int(hex_color[2] * 2, 16)
1026
+ a = 1.0
1027
+ elif hex_length in (6, 8): # Full hex format (#RRGGBB)
1028
+ r = int(hex_color[0:2], 16)
1029
+ g = int(hex_color[2:4], 16)
1030
+ b = int(hex_color[4:6], 16)
1031
+ if hex_length == 8: # With alpha
1032
+ a = int(hex_color[6:8], 16)
1033
+ else:
1034
+ a = 1.0
1035
+ else:
1036
+ raise ValueError("Invalid hex color code format")
1037
+
1038
+ return (r, g, b, a)
1039
+
1040
+
1041
+ dtheme = Theme()
1042
+ """Singleton instance of class ``Theme``."""