nelsie
1from .basictypes import AlignItems, AlignContent, FlexWrap, Stroke, TextAlign 2from .insteps import InSteps 3from .shapes import Arrow, Path 4from .slidedeck import Resources, SlideDeck, Slide 5from .textstyle import FontStretch, TextStyle 6from .box import Box, BoxBuilder 7 8__all__ = [ 9 "SlideDeck", 10 "InSteps", 11 "Path", 12 "Stroke", 13 "TextStyle", 14 "Resources", 15 "FontStretch", 16 "TextAlign", 17 "FlexWrap", 18 "AlignItems", 19 "AlignContent", 20 "Arrow", 21 "BoxBuilder", 22 "Box", 23 "Slide", 24]
69class SlideDeck: 70 def __init__( 71 self, 72 *, 73 width: float = 1024, 74 height: float = 768, 75 bg_color: str = "white", 76 image_directory: str | None = None, 77 resources: Resources | None = None, 78 default_font: str | None = None, 79 default_monospace_font: str | None = None, 80 default_code_theme: str = "InspiredGitHub", 81 default_code_language: str | None = None, 82 ): 83 """ 84 A top-level class of Nelsie. It represents a set of slides. 85 86 Arguments: 87 * width - default width of a slide (could be overriden for each slide) 88 * height - default width of a slide (could be overriden for each slide) 89 * bg_color - default background color a slide (could be overriden for each slide) 90 * image_directory - default path where images are searched for (could be overriden for each slide) 91 * resource - Resource instance, if None a new instance is created 92 * default_font - Name of default font 93 * default_monospace_font - Name of the default monospace font 94 * default_code_theme - Name of default theme for syntax highlighting (.code() method): 95 Available themes: 96 * "base16-ocean.dark" 97 * "base16-eighties.dark" 98 * "base16-mocha.dark" 99 * "base16-ocean.light" 100 * "InspiredGitHub" 101 * "Solarized (dark)" 102 * "Solarized (light)" 103 * default_code_language - Default language to use for syntax highlighting (.code() method) 104 """ 105 if resources is None: 106 resources = Resources() 107 108 self.width = width 109 self.height = height 110 self.bg_color = bg_color 111 self.image_directory = image_directory 112 self.resources = resources 113 self.default_code_theme = default_code_theme 114 self.default_code_language = default_code_language 115 self._deck = nelsie_rs.Deck(resources, default_font, default_monospace_font) 116 117 def set_style(self, name: str, style: TextStyle): 118 self._deck.set_style(self.resources, name, style, False, None, None) 119 120 def update_style(self, name: str, style: TextStyle): 121 self._deck.set_style(self.resources, name, style, True, None, None) 122 123 def get_style(self, name: str, step: int = 1) -> TextStyle: 124 return _data_to_text_style(self._deck.get_style(name, step, None, None)) 125 126 def new_slide( 127 self, 128 *, 129 width: float | None = None, 130 height: float | None = None, 131 bg_color: str | None = None, 132 image_directory: str | None = None, 133 name: str = "", 134 debug_steps: bool = False, 135 debug_layout: bool | str = False, 136 counters: list[str] | None = None, 137 parent_slide: tuple[Slide, int] | None = None, 138 step_1: bool = True, 139 ) -> Slide: 140 """ 141 Creates a new slide in the slide deck. 142 """ 143 if width is None: 144 width = self.width 145 if height is None: 146 height = self.height 147 if bg_color is None: 148 bg_color = self.bg_color 149 if image_directory is None: 150 image_directory = self.image_directory 151 debug_layout = parse_debug_layout(debug_layout) 152 slide_id = self._deck.new_slide(width, height, bg_color, name, step_1, debug_steps, counters, parent_slide) 153 return Slide(self, slide_id, name, image_directory, debug_layout) 154 155 def slide( 156 self, 157 *, 158 width: float | None = None, 159 height: float | None = None, 160 bg_color: str | None = None, 161 image_directory: str | None = None, 162 name: str = "", 163 debug_steps: bool = False, 164 debug_layout: bool | str = False, 165 counters: list[str] | None = None, 166 parent_slide: tuple[Slide, int] | None = None, 167 step_1: bool = True, 168 ): 169 """ 170 Decorator for creating new slide. 171 It immediately calls the decorated function that should define content of the slide. 172 Slide is automatically added into the deck. 173 174 Example: 175 ```python 176 deck = SlideDeck() 177 178 @deck.slide() 179 def my_first_slide(slide): 180 slide.text("Hello!") 181 ``` 182 """ 183 184 def helper(fn): 185 slide = self.new_slide( 186 width=width, 187 height=height, 188 bg_color=bg_color, 189 image_directory=image_directory, 190 name=name, 191 debug_steps=debug_steps, 192 debug_layout=debug_layout, 193 counters=counters, 194 parent_slide=parent_slide, 195 step_1=step_1, 196 ) 197 fn(slide) 198 return slide 199 200 return helper 201 202 def render( 203 self, 204 path: str | pathlib.Path | None, 205 output_format: Literal["pdf"] | Literal["svg"] | Literal["png"] = "pdf", 206 *, 207 verbose: int = 1, 208 n_threads: int | None = None, 209 ) -> None | list[bytes]: 210 """ 211 Render slides 212 213 If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then 214 `path` specifies a directory where the slides are created as an individual files. 215 216 If `path` is None then objects are not written to the file system, and they are returned as python objects 217 from the method call. 218 """ 219 if path: 220 path = str(path) 221 return self._deck.render(self.resources, verbose, output_format, path, n_threads)
70 def __init__( 71 self, 72 *, 73 width: float = 1024, 74 height: float = 768, 75 bg_color: str = "white", 76 image_directory: str | None = None, 77 resources: Resources | None = None, 78 default_font: str | None = None, 79 default_monospace_font: str | None = None, 80 default_code_theme: str = "InspiredGitHub", 81 default_code_language: str | None = None, 82 ): 83 """ 84 A top-level class of Nelsie. It represents a set of slides. 85 86 Arguments: 87 * width - default width of a slide (could be overriden for each slide) 88 * height - default width of a slide (could be overriden for each slide) 89 * bg_color - default background color a slide (could be overriden for each slide) 90 * image_directory - default path where images are searched for (could be overriden for each slide) 91 * resource - Resource instance, if None a new instance is created 92 * default_font - Name of default font 93 * default_monospace_font - Name of the default monospace font 94 * default_code_theme - Name of default theme for syntax highlighting (.code() method): 95 Available themes: 96 * "base16-ocean.dark" 97 * "base16-eighties.dark" 98 * "base16-mocha.dark" 99 * "base16-ocean.light" 100 * "InspiredGitHub" 101 * "Solarized (dark)" 102 * "Solarized (light)" 103 * default_code_language - Default language to use for syntax highlighting (.code() method) 104 """ 105 if resources is None: 106 resources = Resources() 107 108 self.width = width 109 self.height = height 110 self.bg_color = bg_color 111 self.image_directory = image_directory 112 self.resources = resources 113 self.default_code_theme = default_code_theme 114 self.default_code_language = default_code_language 115 self._deck = nelsie_rs.Deck(resources, default_font, default_monospace_font)
A top-level class of Nelsie. It represents a set of slides.
Arguments:
- width - default width of a slide (could be overriden for each slide)
- height - default width of a slide (could be overriden for each slide)
- bg_color - default background color a slide (could be overriden for each slide)
- image_directory - default path where images are searched for (could be overriden for each slide)
- resource - Resource instance, if None a new instance is created
- default_font - Name of default font
- default_monospace_font - Name of the default monospace font
- default_code_theme - Name of default theme for syntax highlighting (.code() method):
Available themes:
- "base16-ocean.dark"
- "base16-eighties.dark"
- "base16-mocha.dark"
- "base16-ocean.light"
- "InspiredGitHub"
- "Solarized (dark)"
- "Solarized (light)"
- default_code_language - Default language to use for syntax highlighting (.code() method)
126 def new_slide( 127 self, 128 *, 129 width: float | None = None, 130 height: float | None = None, 131 bg_color: str | None = None, 132 image_directory: str | None = None, 133 name: str = "", 134 debug_steps: bool = False, 135 debug_layout: bool | str = False, 136 counters: list[str] | None = None, 137 parent_slide: tuple[Slide, int] | None = None, 138 step_1: bool = True, 139 ) -> Slide: 140 """ 141 Creates a new slide in the slide deck. 142 """ 143 if width is None: 144 width = self.width 145 if height is None: 146 height = self.height 147 if bg_color is None: 148 bg_color = self.bg_color 149 if image_directory is None: 150 image_directory = self.image_directory 151 debug_layout = parse_debug_layout(debug_layout) 152 slide_id = self._deck.new_slide(width, height, bg_color, name, step_1, debug_steps, counters, parent_slide) 153 return Slide(self, slide_id, name, image_directory, debug_layout)
Creates a new slide in the slide deck.
155 def slide( 156 self, 157 *, 158 width: float | None = None, 159 height: float | None = None, 160 bg_color: str | None = None, 161 image_directory: str | None = None, 162 name: str = "", 163 debug_steps: bool = False, 164 debug_layout: bool | str = False, 165 counters: list[str] | None = None, 166 parent_slide: tuple[Slide, int] | None = None, 167 step_1: bool = True, 168 ): 169 """ 170 Decorator for creating new slide. 171 It immediately calls the decorated function that should define content of the slide. 172 Slide is automatically added into the deck. 173 174 Example: 175 ```python 176 deck = SlideDeck() 177 178 @deck.slide() 179 def my_first_slide(slide): 180 slide.text("Hello!") 181 ``` 182 """ 183 184 def helper(fn): 185 slide = self.new_slide( 186 width=width, 187 height=height, 188 bg_color=bg_color, 189 image_directory=image_directory, 190 name=name, 191 debug_steps=debug_steps, 192 debug_layout=debug_layout, 193 counters=counters, 194 parent_slide=parent_slide, 195 step_1=step_1, 196 ) 197 fn(slide) 198 return slide 199 200 return helper
Decorator for creating new slide. It immediately calls the decorated function that should define content of the slide. Slide is automatically added into the deck.
Example:
deck = SlideDeck()
@deck.slide()
def my_first_slide(slide):
slide.text("Hello!")
202 def render( 203 self, 204 path: str | pathlib.Path | None, 205 output_format: Literal["pdf"] | Literal["svg"] | Literal["png"] = "pdf", 206 *, 207 verbose: int = 1, 208 n_threads: int | None = None, 209 ) -> None | list[bytes]: 210 """ 211 Render slides 212 213 If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then 214 `path` specifies a directory where the slides are created as an individual files. 215 216 If `path` is None then objects are not written to the file system, and they are returned as python objects 217 from the method call. 218 """ 219 if path: 220 path = str(path) 221 return self._deck.render(self.resources, verbose, output_format, path, n_threads)
Render slides
If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then
path
specifies a directory where the slides are created as an individual files.
If path
is None then objects are not written to the file system, and they are returned as python objects
from the method call.
10class InSteps(Generic[T]): 11 """ 12 InSteps is a wrapper that allows to set a different values for each step. 13 InSteps defines values in "key" steps, in other steps the value remains until it is changed 14 another key step. 15 16 Example: 17 ```python 18 slide.box(..., bg_color=InSteps({1: "green", 4: "red"}) 19 ``` 20 21 Defines "green" background for steps 1, 2, 3; and "red" for step 4 and further. 22 23 InSteps can be also initialized by a list, then it defines values for first `n` steps, 24 where `n` is a length of the list. It means that `InSteps(["a", "b", "c"])` is equal to 25 `InSteps({1: "a", 2: "b", 3: "c"})` 26 """ 27 28 def __init__( 29 self, 30 values: Sequence[T] | dict[Step | int, T], 31 ): 32 if isinstance(values, Sequence): 33 tmp = {} 34 prev = None 35 for i, v in enumerate(values): 36 if i != 0 and v == prev: 37 continue 38 tmp[i + 1] = v 39 prev = v 40 values = tmp 41 elif not isinstance(values, dict): 42 raise ValueError("Invalid type for values") 43 self.in_step_values = values 44 45 def get(self, step: int, default: S = None) -> T | None: 46 v = self.in_step_values.get(step) 47 if v is not None: 48 return v 49 if step <= 0: 50 return default 51 return self.get(step - 1, default) 52 53 def map(self, fn): 54 return InSteps( 55 {step: fn(v) for step, v in self.in_step_values.items()}, 56 ) 57 58 def key_steps(self): 59 return self.in_step_values.keys() 60 61 def zip(self, other: "InSteps[S]") -> "InSteps[tuple[S, T]]": 62 keys = set(self.key_steps()) 63 keys.update(other.key_steps()) 64 return InSteps( 65 {step: (self.get(step), other.get(step)) for step in keys}, 66 )
InSteps is a wrapper that allows to set a different values for each step. InSteps defines values in "key" steps, in other steps the value remains until it is changed another key step.
Example:
slide.box(..., bg_color=InSteps({1: "green", 4: "red"})
Defines "green" background for steps 1, 2, 3; and "red" for step 4 and further.
InSteps can be also initialized by a list, then it defines values for first n
steps,
where n
is a length of the list. It means that InSteps(["a", "b", "c"])
is equal to
InSteps({1: "a", 2: "b", 3: "c"})
28 def __init__( 29 self, 30 values: Sequence[T] | dict[Step | int, T], 31 ): 32 if isinstance(values, Sequence): 33 tmp = {} 34 prev = None 35 for i, v in enumerate(values): 36 if i != 0 and v == prev: 37 continue 38 tmp[i + 1] = v 39 prev = v 40 values = tmp 41 elif not isinstance(values, dict): 42 raise ValueError("Invalid type for values") 43 self.in_step_values = values
37class Path: 38 def __init__( 39 self, 40 *, 41 stroke: Stroke | None = None, 42 fill_color: str | None = None, 43 arrow_start: Arrow | None = None, 44 arrow_end: Arrow | None = None, 45 ): 46 self.stroke = stroke 47 self.fill_color = fill_color 48 self.commands = [] 49 self.points = [] 50 self.arrow_start = arrow_start 51 self.arrow_end = arrow_end 52 53 @staticmethod 54 def oval( 55 x1: PathValue, 56 y1: PathValue, 57 x2: PathValue, 58 y2: PathValue, 59 *, 60 stroke: Stroke | None = None, 61 fill_color: str | None = None, 62 ): 63 path = Path(stroke=stroke, fill_color=fill_color) 64 path.commands.append("oval") 65 path.points = [x1, y1, x2, y2] 66 return path 67 68 def close(self): 69 self.commands.append("close") 70 return self 71 72 def move_to(self, x: PathValue, y: PathValue): 73 self.commands.append("move") 74 self.points.append(x) 75 self.points.append(y) 76 return self 77 78 def line_to(self, x: PathValue, y: PathValue): 79 self.commands.append("line") 80 self.points.append(x) 81 self.points.append(y) 82 return self 83 84 def quad_to(self, x1: PathValue, y1: PathValue, x: PathValue, y: PathValue): 85 self.commands.append("quad") 86 self.points.append(x1) 87 self.points.append(y1) 88 self.points.append(x) 89 self.points.append(y) 90 return self 91 92 def cubic_to( 93 self, 94 x1: PathValue, 95 y1: PathValue, 96 x2: PathValue, 97 y2: PathValue, 98 x: PathValue, 99 y: PathValue, 100 ): 101 self.commands.append("cubic") 102 self.points.append(x1) 103 self.points.append(y1) 104 self.points.append(x2) 105 self.points.append(y2) 106 self.points.append(x) 107 self.points.append(y) 108 return self
38 def __init__( 39 self, 40 *, 41 stroke: Stroke | None = None, 42 fill_color: str | None = None, 43 arrow_start: Arrow | None = None, 44 arrow_end: Arrow | None = None, 45 ): 46 self.stroke = stroke 47 self.fill_color = fill_color 48 self.commands = [] 49 self.points = [] 50 self.arrow_start = arrow_start 51 self.arrow_end = arrow_end
53 @staticmethod 54 def oval( 55 x1: PathValue, 56 y1: PathValue, 57 x2: PathValue, 58 y2: PathValue, 59 *, 60 stroke: Stroke | None = None, 61 fill_color: str | None = None, 62 ): 63 path = Path(stroke=stroke, fill_color=fill_color) 64 path.commands.append("oval") 65 path.points = [x1, y1, x2, y2] 66 return path
92 def cubic_to( 93 self, 94 x1: PathValue, 95 y1: PathValue, 96 x2: PathValue, 97 y2: PathValue, 98 x: PathValue, 99 y: PathValue, 100 ): 101 self.commands.append("cubic") 102 self.points.append(x1) 103 self.points.append(y1) 104 self.points.append(x2) 105 self.points.append(y2) 106 self.points.append(x) 107 self.points.append(y) 108 return self
14@dataclass 15class Stroke: 16 color: str 17 width: float = 1.0 18 dash_array: list[float] | None = None 19 dash_offset: float = 0.0
22@dataclass(frozen=True) 23class TextStyle: 24 font_family: str | list[str] | None = None 25 color: str | Literal["empty"] | None = None 26 stroke: Stroke | Literal["empty"] | None = None 27 size: float | None = None 28 line_spacing: float | None = None 29 italic: bool | None = None 30 stretch: FontStretch | None = None 31 underline: bool | None = None 32 overline: bool | None = None 33 line_through: bool | None = None 34 35 # 1-1000; 400 = Normal, 700 = Bold 36 weight: int | None = None 37 38 def __post_init__(self): 39 if self.size is not None: 40 assert self.size >= 0 41 if self.line_spacing is not None: 42 assert self.line_spacing >= 0 43 if self.weight is not None: 44 assert 1 <= self.weight <= 1000 45 46 def merge(self, other: "TextStyle") -> "TextStyle": 47 assert isinstance(other, TextStyle) 48 return TextStyle( 49 *[b if b is not None else a for (a, b) in zip(unpack_dataclass(self), unpack_dataclass(other))] 50 )
10class FontStretch(IntEnum): 11 UltraCondensed = 1 12 ExtraCondensed = 2 13 Condensed = 3 14 SemiCondensed = 4 15 Normal = 5 16 SemiExpanded = 6 17 Expanded = 7 18 ExtraExpanded = 8 19 UltraExpanded = 9
An enumeration.
Inherited Members
- enum.Enum
- name
- value
- builtins.int
- conjugate
- bit_length
- bit_count
- to_bytes
- from_bytes
- as_integer_ratio
- real
- imag
- numerator
- denominator
10@dataclass 11class Arrow: 12 """ 13 Represents an SVG arrow head. Can be attached to the start or end points of lines. 14 """ 15 16 size: float = 10 17 """Size of the arrow head in pixels.""" 18 19 angle: float = 40 20 """Angle of the arrow head.""" 21 22 color: str | None = None 23 """Color of arrow, if None color is taken from path""" 24 25 stroke_width: float | None = None 26 """If None then a filled arrow is drawn, if float then stroked arrow is drawn with the given stroke width""" 27 28 inner_point: float | None = None 29 """ Shape of the arrow head. 30 31 * < 1.0 -> Sharper arrow. 32 * = 1.0 -> Normal arrow. 33 * > 1.0 -> Diamond shape arrow. 34 """
Represents an SVG arrow head. Can be attached to the start or end points of lines.
50class BoxBuilder: 51 def get_box(self): 52 """ 53 @private 54 """ 55 raise NotImplementedError 56 57 def set_style(self, name: str, style: TextStyle | InSteps[TextStyle]): 58 """ 59 Set text style under given name. 60 """ 61 box = self.get_box() 62 deck = box.deck 63 deck._deck.set_style(deck.resources, name, style, False, box.slide._slide_id, box._box_id) 64 65 def update_style(self, name: str, style: TextStyle | InSteps[TextStyle]): 66 """ 67 Load a text style and merge it with the `style` and save it back. 68 Throws an exception if a style under given name does not exist. 69 """ 70 box = self.get_box() 71 deck = box.deck 72 deck._deck.set_style(deck.resources, name, style, True, box.slide._slide_id, box._box_id) 73 74 def get_style(self, name: str, step: int = 1) -> TextStyle: 75 """ 76 Get text style under given name. Style is returned for a given `step`. 77 Throws an exception if a style under given name does not exist. 78 79 This function returns text style even when InSteps was used to set the style, 80 as it returns text style for a given step. 81 """ 82 83 box = self.get_box() 84 return _data_to_text_style(box.deck._deck.get_style(name, step, box.slide._slide_id, box._box_id)) 85 86 def image(self, path: str | None | InSteps[str | None], enable_steps=True, shift_steps=0, **box_args): 87 """ 88 Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA 89 """ 90 assert shift_steps >= 0 91 92 def process_path(p): 93 if p is None: 94 return None 95 if slide.image_directory is not None: 96 p = os.path.join(slide.image_directory, p) 97 p = os.path.abspath(p) 98 watch_path(p) 99 return p 100 101 slide = self.get_box().slide 102 if isinstance(path, InSteps): 103 path = path.map(process_path) 104 else: 105 path = process_path(path) 106 image = ImageContent( 107 path=path, 108 enable_steps=enable_steps, 109 shift_steps=shift_steps, 110 ) 111 return self.box(_content=image, **box_args) 112 113 def text( 114 self, 115 text: str | InSteps[str], 116 style: str | TextStyle | InSteps[TextStyle] | None = None, 117 *, 118 parse_styles: bool = True, 119 style_delimiters: str | None = "~{}", 120 tab_width: int = 4, 121 align: TextAlign = "start", 122 strip=True, 123 parse_counters: bool = False, 124 **box_args, 125 ): 126 """ 127 Create a box with a text. 128 """ 129 box_args.setdefault("name", "text") 130 return self._text_box( 131 text, 132 style, 133 None, 134 style_delimiters if parse_styles else None, 135 tab_width, 136 box_args, 137 align, 138 None, 139 None, 140 strip, 141 parse_counters, 142 ) 143 144 def code( 145 self, 146 text: str | InSteps[str], 147 language: str | None = "default", 148 style: str | TextStyle | InSteps[TextStyle] | None = None, 149 *, 150 theme: str | None = None, 151 parse_styles: bool = False, 152 style_delimiters: str | None = "~{}", 153 tab_width: int = 4, 154 align: TextAlign = "start", 155 strip: bool = True, 156 parse_counters: bool = False, 157 **box_args, 158 ): 159 """ 160 Create a box with a syntax highlighted text. 161 """ 162 box_args.setdefault("name", "code") 163 if theme is None: 164 theme = self.get_box().deck.default_code_theme 165 if language == "default": 166 language = self.get_box().deck.default_code_language 167 return self._text_box( 168 text, 169 "code", 170 style, 171 style_delimiters if parse_styles else None, 172 tab_width, 173 box_args, 174 align, 175 language, 176 theme, 177 strip, 178 parse_counters, 179 ) 180 181 def _text_box( 182 self, 183 text, 184 style1, 185 style2, 186 delimiters, 187 tab_width, 188 box_args, 189 align, 190 language, 191 theme, 192 strip, 193 parse_counters, 194 ): 195 def text_preprocess(x): 196 if strip: 197 x = x.strip() 198 return x.replace("\t", " " * tab_width) 199 200 if isinstance(text, str): 201 text = text_preprocess(text) 202 elif isinstance(text, list): 203 text = zip_in_steps(text, "").map(lambda x: text_preprocess("".join(x))) 204 elif isinstance(text, InSteps): 205 text = text.map(text_preprocess) 206 else: 207 raise Exception("Invalid type for text") 208 209 if align == "start": 210 align = 0 211 elif align == "center": 212 align = 1 213 elif align == "end": 214 align = 2 215 else: 216 raise Exception(f"Invalid alignment: {align}") 217 text_content = TextContent( 218 text=text, 219 style1=style1, 220 style2=style2, 221 formatting_delimiters=delimiters, 222 text_align=align, 223 syntax_language=language, 224 syntax_theme=theme, 225 parse_counters=parse_counters, 226 ) 227 return self.box(_content=text_content, **box_args) 228 229 def draw(self, paths: Path | list[Path] | InSteps[Path | list[Path]]): 230 """ 231 Draw one or paths in the slide. 232 """ 233 234 if isinstance(paths, Path): 235 paths = [paths] 236 elif isinstance(paths, InSteps): 237 paths = paths.map(lambda p: [p] if isinstance(p, Path) else p) 238 box = self.get_box() 239 box.deck._deck.draw(box.slide._slide_id, box._box_id, paths) 240 241 def box( 242 self, 243 *, 244 active: bool | str | int | InSteps[bool] = True, 245 show: bool | str | int | InSteps[bool] = True, 246 z_level: int | InSteps[int] | None = None, 247 x: Position | InSteps[Position] = None, 248 y: Position | InSteps[Position] = None, 249 width: Size | InSteps[Size] = None, 250 height: Size | InSteps[Size] = None, 251 border_radius: float | InSteps[float] = 0, 252 p_left: Length | InSteps[Length] | None = None, 253 p_right: Length | InSteps[Length] | None = None, 254 p_top: Length | InSteps[Length] | None = None, 255 p_bottom: Length | InSteps[Length] | None = None, 256 p_x: Length | InSteps[Length] = 0, 257 p_y: Length | InSteps[Length] = 0, 258 m_left: LengthAuto | InSteps[LengthAuto] | None = None, 259 m_right: LengthAuto | InSteps[LengthAuto] | None = None, 260 m_top: LengthAuto | InSteps[LengthAuto] | None = None, 261 m_bottom: LengthAuto | InSteps[LengthAuto] | None = None, 262 m_x: LengthAuto | InSteps[LengthAuto] = 0, 263 m_y: LengthAuto | InSteps[LengthAuto] = 0, 264 row: bool | InSteps[bool] = False, 265 reverse: bool | InSteps[bool] = False, 266 flex_wrap: FlexWrap | InSteps[FlexWrap] = "nowrap", 267 flex_grow: float | InSteps[float] = 0.0, 268 flex_shrink: float | InSteps[float] = 1.0, 269 align_items: AlignItemsSteps = None, 270 align_self: AlignItemsSteps = None, 271 justify_self: AlignItemsSteps = None, 272 align_content: AlignContentSteps = None, 273 justify_content: AlignContentSteps = None, 274 gap: tuple[Length, Length] | InSteps[tuple[Length, Length]] = (0.0, 0.0), 275 grid_template_rows: GridTemplate = (), 276 grid_template_columns: GridTemplate = (), 277 grid_row: GridPosition = "auto", 278 grid_column: GridPosition = "auto", 279 bg_color: str | None | InSteps[str | None] = None, 280 url: None | str | InSteps[None | str] = None, 281 name: str = "", 282 debug_layout: bool | str | None = None, 283 replace_steps: dict[int, int] | None = None, 284 _content: NodeContent | InSteps[NodeContent] = None, 285 ): 286 """ 287 Create a new child box. See [Box reference](https://spirali.github.io/nelsie/guide/box/) for documentation 288 """ 289 parent_box = self.get_box() 290 if debug_layout is None: 291 debug_layout = parent_box.slide.debug_layout 292 else: 293 debug_layout = parse_debug_layout(debug_layout) 294 if z_level is None: 295 z_level = parent_box.z_level 296 297 if p_left is None: 298 p_left = p_x 299 if p_right is None: 300 p_right = p_x 301 if p_bottom is None: 302 p_bottom = p_y 303 if p_top is None: 304 p_top = p_y 305 306 if m_left is None: 307 m_left = m_x 308 if m_right is None: 309 m_right = m_x 310 if m_bottom is None: 311 m_bottom = m_y 312 if m_top is None: 313 m_top = m_y 314 315 deck = parent_box.deck 316 box_id, node_id = deck._deck.new_box( 317 deck.resources, 318 parent_box.slide._slide_id, 319 parent_box._box_id, 320 active=active, 321 show=show, 322 z_level=z_level, 323 x=x, 324 y=y, 325 width=width, 326 height=height, 327 border_radius=border_radius, 328 p_left=p_left, 329 p_right=p_right, 330 p_top=p_top, 331 p_bottom=p_bottom, 332 m_left=m_left, 333 m_right=m_right, 334 m_top=m_top, 335 m_bottom=m_bottom, 336 row=row, 337 reverse=reverse, 338 flex_wrap=flex_wrap, 339 flex_grow=flex_grow, 340 flex_shrink=flex_shrink, 341 align_items=align_items, 342 align_self=align_self, 343 justify_self=justify_self, 344 align_content=align_content, 345 justify_content=justify_content, 346 gap=gap, 347 grid_template_rows=grid_template_rows, 348 grid_template_columns=grid_template_columns, 349 grid_row=grid_row, 350 grid_column=grid_column, 351 bg_color=bg_color, 352 url=url, 353 name=name, 354 debug_layout=debug_layout, 355 replace_steps=replace_steps, 356 content=_content, 357 ) 358 return Box(deck, parent_box.slide, box_id, node_id, name, z_level) 359 360 def overlay(self, **box_args): 361 """ 362 Create a new box that spans over the box 363 """ 364 box_args.setdefault("x", 0) 365 box_args.setdefault("y", 0) 366 box_args.setdefault("width", "100%") 367 box_args.setdefault("height", "100%") 368 return self.box(**box_args) 369 370 def line_box(self, line_idx: int, **box_args): 371 """ 372 Creates a new box over a text line in the box 373 """ 374 return self.box( 375 x=self.line_x(line_idx), 376 y=self.line_y(line_idx), 377 width=self.line_width(line_idx), 378 height=self.line_height(line_idx), 379 **box_args, 380 ) 381 382 def text_anchor_box(self, anchor_id: int, **box_args): 383 """ 384 Creates a new box over a text anchor in the box 385 """ 386 387 return self.box( 388 x=self.text_anchor_x(anchor_id), 389 y=self.text_anchor_y(anchor_id), 390 width=self.text_anchor_width(anchor_id), 391 height=self.text_anchor_height(anchor_id), 392 **box_args, 393 ) 394 395 def x(self, width_fraction: float | int | None = None) -> LayoutExpr: 396 """ 397 Get an expression with X coordinate relative to the box. 398 """ 399 400 node_id = self.get_box().node_id 401 expr = LayoutExpr.x(node_id) 402 if width_fraction is None: 403 return expr 404 return expr + LayoutExpr.width(node_id, width_fraction) 405 406 def y(self, height_fraction: float | int | None = None) -> LayoutExpr: 407 """ 408 Get an expression with Y coordinate relative to the box. 409 """ 410 node_id = self.get_box().node_id 411 expr = LayoutExpr.y(node_id) 412 if height_fraction is None: 413 return expr 414 return expr + LayoutExpr.height(node_id, height_fraction) 415 416 def width(self, fraction: float | int = 1.0) -> LayoutExpr: 417 """ 418 Get an expression with width of the parent box. 419 """ 420 node_id = self.get_box().node_id 421 return LayoutExpr.width(node_id, fraction) 422 423 def height(self, fraction: float | int = 1.0) -> LayoutExpr: 424 """ 425 Get an expression with height of the parent box. 426 """ 427 node_id = self.get_box().node_id 428 return LayoutExpr.height(node_id, fraction) 429 430 def line_x(self, line_idx: int, width_fraction: float | int | None = None) -> LayoutExpr: 431 """ 432 Get an expression with X coordinate of a given line of text in the box. 433 """ 434 node_id = self.get_box().node_id 435 expr = LayoutExpr.line_x(node_id, line_idx) 436 if width_fraction is None: 437 return expr 438 return expr + LayoutExpr.line_width(node_id, line_idx, width_fraction) 439 440 def line_y(self, line_idx: int, height_fraction: float | int | None = None) -> LayoutExpr: 441 """ 442 Get an expression with Y coordinate of a given line of text in the box. 443 """ 444 node_id = self.get_box().node_id 445 expr = LayoutExpr.line_y(node_id, line_idx) 446 if height_fraction is None: 447 return expr 448 return expr + LayoutExpr.line_height(node_id, line_idx, height_fraction) 449 450 def line_width(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr: 451 """ 452 Get an expression with a width of a given line of text in the box. 453 """ 454 node_id = self.get_box().node_id 455 return LayoutExpr.line_width(node_id, line_idx, fraction) 456 457 def line_height(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr: 458 """ 459 Get an expression with a height of a given line of text in the box. 460 """ 461 node_id = self.get_box().node_id 462 return LayoutExpr.line_height(node_id, line_idx, fraction) 463 464 def text_anchor_x(self, anchor_id: int, width_fraction: float | int | None = None) -> LayoutExpr: 465 """ 466 Get an expression with X coordinate of a given text anchor in the box. 467 """ 468 node_id = self.get_box().node_id 469 expr = LayoutExpr.text_anchor_x(node_id, anchor_id) 470 if width_fraction is None: 471 return expr 472 return expr + LayoutExpr.text_anchor_width(node_id, anchor_id, width_fraction) 473 474 def text_anchor_y(self, anchor_id: int, height_fraction: float | int | None = None) -> LayoutExpr: 475 """ 476 Get an expression with Y coordinate of a given text anchor in the box. 477 """ 478 node_id = self.get_box().node_id 479 expr = LayoutExpr.text_anchor_y(node_id, anchor_id) 480 if height_fraction is None: 481 return expr 482 return expr + LayoutExpr.text_anchor_height(node_id, anchor_id, height_fraction) 483 484 def text_anchor_width(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr: 485 """ 486 Get an expression with a height of a given text anchor in the box. 487 """ 488 node_id = self.get_box().node_id 489 return LayoutExpr.text_anchor_width(node_id, anchor_id, fraction) 490 491 def text_anchor_height(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr: 492 """ 493 Get an expression with a height of a given text anchor in the box. 494 """ 495 node_id = self.get_box().node_id 496 return LayoutExpr.text_anchor_height(node_id, anchor_id, fraction)
57 def set_style(self, name: str, style: TextStyle | InSteps[TextStyle]): 58 """ 59 Set text style under given name. 60 """ 61 box = self.get_box() 62 deck = box.deck 63 deck._deck.set_style(deck.resources, name, style, False, box.slide._slide_id, box._box_id)
Set text style under given name.
65 def update_style(self, name: str, style: TextStyle | InSteps[TextStyle]): 66 """ 67 Load a text style and merge it with the `style` and save it back. 68 Throws an exception if a style under given name does not exist. 69 """ 70 box = self.get_box() 71 deck = box.deck 72 deck._deck.set_style(deck.resources, name, style, True, box.slide._slide_id, box._box_id)
Load a text style and merge it with the style
and save it back.
Throws an exception if a style under given name does not exist.
74 def get_style(self, name: str, step: int = 1) -> TextStyle: 75 """ 76 Get text style under given name. Style is returned for a given `step`. 77 Throws an exception if a style under given name does not exist. 78 79 This function returns text style even when InSteps was used to set the style, 80 as it returns text style for a given step. 81 """ 82 83 box = self.get_box() 84 return _data_to_text_style(box.deck._deck.get_style(name, step, box.slide._slide_id, box._box_id))
Get text style under given name. Style is returned for a given step
.
Throws an exception if a style under given name does not exist.
This function returns text style even when InSteps was used to set the style, as it returns text style for a given step.
86 def image(self, path: str | None | InSteps[str | None], enable_steps=True, shift_steps=0, **box_args): 87 """ 88 Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA 89 """ 90 assert shift_steps >= 0 91 92 def process_path(p): 93 if p is None: 94 return None 95 if slide.image_directory is not None: 96 p = os.path.join(slide.image_directory, p) 97 p = os.path.abspath(p) 98 watch_path(p) 99 return p 100 101 slide = self.get_box().slide 102 if isinstance(path, InSteps): 103 path = path.map(process_path) 104 else: 105 path = process_path(path) 106 image = ImageContent( 107 path=path, 108 enable_steps=enable_steps, 109 shift_steps=shift_steps, 110 ) 111 return self.box(_content=image, **box_args)
Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA
113 def text( 114 self, 115 text: str | InSteps[str], 116 style: str | TextStyle | InSteps[TextStyle] | None = None, 117 *, 118 parse_styles: bool = True, 119 style_delimiters: str | None = "~{}", 120 tab_width: int = 4, 121 align: TextAlign = "start", 122 strip=True, 123 parse_counters: bool = False, 124 **box_args, 125 ): 126 """ 127 Create a box with a text. 128 """ 129 box_args.setdefault("name", "text") 130 return self._text_box( 131 text, 132 style, 133 None, 134 style_delimiters if parse_styles else None, 135 tab_width, 136 box_args, 137 align, 138 None, 139 None, 140 strip, 141 parse_counters, 142 )
Create a box with a text.
144 def code( 145 self, 146 text: str | InSteps[str], 147 language: str | None = "default", 148 style: str | TextStyle | InSteps[TextStyle] | None = None, 149 *, 150 theme: str | None = None, 151 parse_styles: bool = False, 152 style_delimiters: str | None = "~{}", 153 tab_width: int = 4, 154 align: TextAlign = "start", 155 strip: bool = True, 156 parse_counters: bool = False, 157 **box_args, 158 ): 159 """ 160 Create a box with a syntax highlighted text. 161 """ 162 box_args.setdefault("name", "code") 163 if theme is None: 164 theme = self.get_box().deck.default_code_theme 165 if language == "default": 166 language = self.get_box().deck.default_code_language 167 return self._text_box( 168 text, 169 "code", 170 style, 171 style_delimiters if parse_styles else None, 172 tab_width, 173 box_args, 174 align, 175 language, 176 theme, 177 strip, 178 parse_counters, 179 )
Create a box with a syntax highlighted text.
229 def draw(self, paths: Path | list[Path] | InSteps[Path | list[Path]]): 230 """ 231 Draw one or paths in the slide. 232 """ 233 234 if isinstance(paths, Path): 235 paths = [paths] 236 elif isinstance(paths, InSteps): 237 paths = paths.map(lambda p: [p] if isinstance(p, Path) else p) 238 box = self.get_box() 239 box.deck._deck.draw(box.slide._slide_id, box._box_id, paths)
Draw one or paths in the slide.
241 def box( 242 self, 243 *, 244 active: bool | str | int | InSteps[bool] = True, 245 show: bool | str | int | InSteps[bool] = True, 246 z_level: int | InSteps[int] | None = None, 247 x: Position | InSteps[Position] = None, 248 y: Position | InSteps[Position] = None, 249 width: Size | InSteps[Size] = None, 250 height: Size | InSteps[Size] = None, 251 border_radius: float | InSteps[float] = 0, 252 p_left: Length | InSteps[Length] | None = None, 253 p_right: Length | InSteps[Length] | None = None, 254 p_top: Length | InSteps[Length] | None = None, 255 p_bottom: Length | InSteps[Length] | None = None, 256 p_x: Length | InSteps[Length] = 0, 257 p_y: Length | InSteps[Length] = 0, 258 m_left: LengthAuto | InSteps[LengthAuto] | None = None, 259 m_right: LengthAuto | InSteps[LengthAuto] | None = None, 260 m_top: LengthAuto | InSteps[LengthAuto] | None = None, 261 m_bottom: LengthAuto | InSteps[LengthAuto] | None = None, 262 m_x: LengthAuto | InSteps[LengthAuto] = 0, 263 m_y: LengthAuto | InSteps[LengthAuto] = 0, 264 row: bool | InSteps[bool] = False, 265 reverse: bool | InSteps[bool] = False, 266 flex_wrap: FlexWrap | InSteps[FlexWrap] = "nowrap", 267 flex_grow: float | InSteps[float] = 0.0, 268 flex_shrink: float | InSteps[float] = 1.0, 269 align_items: AlignItemsSteps = None, 270 align_self: AlignItemsSteps = None, 271 justify_self: AlignItemsSteps = None, 272 align_content: AlignContentSteps = None, 273 justify_content: AlignContentSteps = None, 274 gap: tuple[Length, Length] | InSteps[tuple[Length, Length]] = (0.0, 0.0), 275 grid_template_rows: GridTemplate = (), 276 grid_template_columns: GridTemplate = (), 277 grid_row: GridPosition = "auto", 278 grid_column: GridPosition = "auto", 279 bg_color: str | None | InSteps[str | None] = None, 280 url: None | str | InSteps[None | str] = None, 281 name: str = "", 282 debug_layout: bool | str | None = None, 283 replace_steps: dict[int, int] | None = None, 284 _content: NodeContent | InSteps[NodeContent] = None, 285 ): 286 """ 287 Create a new child box. See [Box reference](https://spirali.github.io/nelsie/guide/box/) for documentation 288 """ 289 parent_box = self.get_box() 290 if debug_layout is None: 291 debug_layout = parent_box.slide.debug_layout 292 else: 293 debug_layout = parse_debug_layout(debug_layout) 294 if z_level is None: 295 z_level = parent_box.z_level 296 297 if p_left is None: 298 p_left = p_x 299 if p_right is None: 300 p_right = p_x 301 if p_bottom is None: 302 p_bottom = p_y 303 if p_top is None: 304 p_top = p_y 305 306 if m_left is None: 307 m_left = m_x 308 if m_right is None: 309 m_right = m_x 310 if m_bottom is None: 311 m_bottom = m_y 312 if m_top is None: 313 m_top = m_y 314 315 deck = parent_box.deck 316 box_id, node_id = deck._deck.new_box( 317 deck.resources, 318 parent_box.slide._slide_id, 319 parent_box._box_id, 320 active=active, 321 show=show, 322 z_level=z_level, 323 x=x, 324 y=y, 325 width=width, 326 height=height, 327 border_radius=border_radius, 328 p_left=p_left, 329 p_right=p_right, 330 p_top=p_top, 331 p_bottom=p_bottom, 332 m_left=m_left, 333 m_right=m_right, 334 m_top=m_top, 335 m_bottom=m_bottom, 336 row=row, 337 reverse=reverse, 338 flex_wrap=flex_wrap, 339 flex_grow=flex_grow, 340 flex_shrink=flex_shrink, 341 align_items=align_items, 342 align_self=align_self, 343 justify_self=justify_self, 344 align_content=align_content, 345 justify_content=justify_content, 346 gap=gap, 347 grid_template_rows=grid_template_rows, 348 grid_template_columns=grid_template_columns, 349 grid_row=grid_row, 350 grid_column=grid_column, 351 bg_color=bg_color, 352 url=url, 353 name=name, 354 debug_layout=debug_layout, 355 replace_steps=replace_steps, 356 content=_content, 357 ) 358 return Box(deck, parent_box.slide, box_id, node_id, name, z_level)
Create a new child box. See Box reference for documentation
360 def overlay(self, **box_args): 361 """ 362 Create a new box that spans over the box 363 """ 364 box_args.setdefault("x", 0) 365 box_args.setdefault("y", 0) 366 box_args.setdefault("width", "100%") 367 box_args.setdefault("height", "100%") 368 return self.box(**box_args)
Create a new box that spans over the box
370 def line_box(self, line_idx: int, **box_args): 371 """ 372 Creates a new box over a text line in the box 373 """ 374 return self.box( 375 x=self.line_x(line_idx), 376 y=self.line_y(line_idx), 377 width=self.line_width(line_idx), 378 height=self.line_height(line_idx), 379 **box_args, 380 )
Creates a new box over a text line in the box
382 def text_anchor_box(self, anchor_id: int, **box_args): 383 """ 384 Creates a new box over a text anchor in the box 385 """ 386 387 return self.box( 388 x=self.text_anchor_x(anchor_id), 389 y=self.text_anchor_y(anchor_id), 390 width=self.text_anchor_width(anchor_id), 391 height=self.text_anchor_height(anchor_id), 392 **box_args, 393 )
Creates a new box over a text anchor in the box
395 def x(self, width_fraction: float | int | None = None) -> LayoutExpr: 396 """ 397 Get an expression with X coordinate relative to the box. 398 """ 399 400 node_id = self.get_box().node_id 401 expr = LayoutExpr.x(node_id) 402 if width_fraction is None: 403 return expr 404 return expr + LayoutExpr.width(node_id, width_fraction)
Get an expression with X coordinate relative to the box.
406 def y(self, height_fraction: float | int | None = None) -> LayoutExpr: 407 """ 408 Get an expression with Y coordinate relative to the box. 409 """ 410 node_id = self.get_box().node_id 411 expr = LayoutExpr.y(node_id) 412 if height_fraction is None: 413 return expr 414 return expr + LayoutExpr.height(node_id, height_fraction)
Get an expression with Y coordinate relative to the box.
416 def width(self, fraction: float | int = 1.0) -> LayoutExpr: 417 """ 418 Get an expression with width of the parent box. 419 """ 420 node_id = self.get_box().node_id 421 return LayoutExpr.width(node_id, fraction)
Get an expression with width of the parent box.
423 def height(self, fraction: float | int = 1.0) -> LayoutExpr: 424 """ 425 Get an expression with height of the parent box. 426 """ 427 node_id = self.get_box().node_id 428 return LayoutExpr.height(node_id, fraction)
Get an expression with height of the parent box.
430 def line_x(self, line_idx: int, width_fraction: float | int | None = None) -> LayoutExpr: 431 """ 432 Get an expression with X coordinate of a given line of text in the box. 433 """ 434 node_id = self.get_box().node_id 435 expr = LayoutExpr.line_x(node_id, line_idx) 436 if width_fraction is None: 437 return expr 438 return expr + LayoutExpr.line_width(node_id, line_idx, width_fraction)
Get an expression with X coordinate of a given line of text in the box.
440 def line_y(self, line_idx: int, height_fraction: float | int | None = None) -> LayoutExpr: 441 """ 442 Get an expression with Y coordinate of a given line of text in the box. 443 """ 444 node_id = self.get_box().node_id 445 expr = LayoutExpr.line_y(node_id, line_idx) 446 if height_fraction is None: 447 return expr 448 return expr + LayoutExpr.line_height(node_id, line_idx, height_fraction)
Get an expression with Y coordinate of a given line of text in the box.
450 def line_width(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr: 451 """ 452 Get an expression with a width of a given line of text in the box. 453 """ 454 node_id = self.get_box().node_id 455 return LayoutExpr.line_width(node_id, line_idx, fraction)
Get an expression with a width of a given line of text in the box.
457 def line_height(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr: 458 """ 459 Get an expression with a height of a given line of text in the box. 460 """ 461 node_id = self.get_box().node_id 462 return LayoutExpr.line_height(node_id, line_idx, fraction)
Get an expression with a height of a given line of text in the box.
464 def text_anchor_x(self, anchor_id: int, width_fraction: float | int | None = None) -> LayoutExpr: 465 """ 466 Get an expression with X coordinate of a given text anchor in the box. 467 """ 468 node_id = self.get_box().node_id 469 expr = LayoutExpr.text_anchor_x(node_id, anchor_id) 470 if width_fraction is None: 471 return expr 472 return expr + LayoutExpr.text_anchor_width(node_id, anchor_id, width_fraction)
Get an expression with X coordinate of a given text anchor in the box.
474 def text_anchor_y(self, anchor_id: int, height_fraction: float | int | None = None) -> LayoutExpr: 475 """ 476 Get an expression with Y coordinate of a given text anchor in the box. 477 """ 478 node_id = self.get_box().node_id 479 expr = LayoutExpr.text_anchor_y(node_id, anchor_id) 480 if height_fraction is None: 481 return expr 482 return expr + LayoutExpr.text_anchor_height(node_id, anchor_id, height_fraction)
Get an expression with Y coordinate of a given text anchor in the box.
484 def text_anchor_width(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr: 485 """ 486 Get an expression with a height of a given text anchor in the box. 487 """ 488 node_id = self.get_box().node_id 489 return LayoutExpr.text_anchor_width(node_id, anchor_id, fraction)
Get an expression with a height of a given text anchor in the box.
491 def text_anchor_height(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr: 492 """ 493 Get an expression with a height of a given text anchor in the box. 494 """ 495 node_id = self.get_box().node_id 496 return LayoutExpr.text_anchor_height(node_id, anchor_id, fraction)
Get an expression with a height of a given text anchor in the box.
499class Box(BoxBuilder): 500 """ 501 The box in slide layout. 502 503 It should be created via calling method `.box()` on a slide or another box. 504 Note that interesting methods came from Box's parent: BoxBuilder. 505 """ 506 507 def __init__( 508 self, 509 deck, 510 slide, 511 box_id, 512 node_id, 513 name: str, 514 z_level: int, 515 ): 516 """ 517 @private 518 """ 519 self.deck = deck 520 self.slide = slide 521 self._box_id = box_id 522 self.node_id = node_id 523 self.name = name 524 self.z_level = z_level 525 526 def get_box(self): 527 """ 528 @private 529 """ 530 return self
The box in slide layout.
It should be created via calling method .box()
on a slide or another box.
Note that interesting methods came from Box's parent: BoxBuilder.
14class Slide(BoxBuilder): 15 """ 16 Represents a slide in a slide deck. 17 18 It should be created via calling method `.new_slide()` on a deck via decorator `@deck.slide()` 19 """ 20 21 def __init__( 22 self, 23 deck: "SlideDeck", 24 slide_id: int, 25 name: str, 26 image_directory: str, 27 debug_layout: str | None, 28 ): 29 """ 30 @private 31 """ 32 self.deck = deck 33 self._slide_id = slide_id 34 self.name = name 35 self.image_directory = image_directory 36 self.debug_layout = debug_layout 37 self.root_box = Box(deck, self, [], 0, name, 0) 38 39 def get_box(self): 40 """ 41 @private 42 """ 43 return self.root_box 44 45 def insert_step(self, value: Step): 46 self.deck._deck.insert_step(self._slide_id, value) 47 48 def remove_step(self, value: Step): 49 self.deck._deck.remove_step(self._slide_id, value) 50 51 def remove_steps_below(self, value: Step): 52 self.deck._deck.remove_steps_below(self._slide_id, value) 53 54 def remove_steps_above(self, value: Step): 55 self.deck._deck.remove_steps_above(self._slide_id, value) 56 57 def get_steps(self) -> list[Step]: 58 return self.deck._deck.get_steps(self._slide_id) 59 60 def new_slide_at(self, step: int, **slide_kwargs): 61 slide_kwargs["parent_slide"] = (self._slide_id, step) 62 return self.deck.new_slide(**slide_kwargs) 63 64 def slide_at(self, step: int, **slide_kwargs): 65 slide_kwargs["parent_slide"] = (self._slide_id, step) 66 return self.deck.slide(**slide_kwargs)
Represents a slide in a slide deck.
It should be created via calling method .new_slide()
on a deck via decorator @deck.slide()