classes.c21_page
1import drawBot 2 3from lib import layout 4from classes import KBox 5 6 7class KPage(KBox): 8 def __init__( 9 self, 10 size: layout.PageSize = "A5", 11 margin: tuple = 5, 12 aside: int = 0, 13 spread: bool = False, 14 render: bool = True, 15 ): 16 """ 17 Extends `classes.c20_box.KBox` to form a page object. 18 19 Args: 20 size: Page size. See `lib.layout.PageSize`. 21 margin: Margin in mm. 22 aside: Width of pagination column. 23 spread: Divide at spine for 2-page PDF view. 24 render: Draw immediately. Otherwise, call `render()` manually. 25 """ 26 super().__init__(size) 27 28 if render: 29 self.render() 30 31 self.aside: int = aside 32 """Width of aside/pagination column.""" 33 self.margin: tuple[int] = layout.mirror(margin) if self.isLeftSide else margin 34 """Margin for the page (mirrored for left side).""" 35 self._isSpread: bool = spread 36 """Used to draw a spine for 2-page PDF view.""" 37 38 self._divide() 39 self._draftBoxes() 40 41 def _draftBoxes(self) -> None: 42 """Set up the frame and body `classes.c20_box.KBox` objects.""" 43 self.frame = KBox(layout.shrink(frame=self.coords, margin=self.margin)) 44 self.body = KBox( 45 layout.shrinkWidth( 46 frame=self.frame.coords, 47 amount=self.aside, 48 origin="right" if self.isRightSide else "left", 49 mode="mm", 50 ) 51 ) 52 53 @property 54 def isLeftSide(self) -> bool: 55 """True if the page is on the left side.""" 56 return layout.pageIsEven() 57 58 @property 59 def isRightSide(self) -> bool: 60 """True if the page is on the right side.""" 61 return not self.isLeftSide 62 63 @property 64 def pageNumber(self) -> int: 65 """The current page number.""" 66 return drawBot.pageCount() 67 68 def fillBackground(self, color: list[int]) -> None: 69 """ 70 Fill the background of the page with a color. 71 72 Args: 73 color: RGB color to fill with. 74 75 Example: 76 ``` 77 page.fillBackground((0.5, 0.5, 0.5)) 78 ``` 79 """ 80 with drawBot.savedState(): 81 drawBot.fill(*color) 82 drawBot.rect(*self.coords) 83 84 self._divide() 85 86 def paginate(self) -> None: 87 """Draw the page number with contextual alignment. Padded to 2 digits.""" 88 drawBot.textBox( 89 str(drawBot.pageCount()).rjust(2, "0"), 90 self.frame.coords, 91 align="left" if self.isRightSide else "right", 92 ) 93 94 def addHeader(self, title: str = None, gap: int = 5) -> None: 95 """ 96 Add a header `classes.c20_box.KBox` to the page. 97 98 Args: 99 title (optional): Text to write in the header. 100 gap: Space between header and body. 101 """ 102 self.header = KBox(layout.draftBar(self.body.coords)) 103 self.body.coords = layout.draftBody( 104 self.body.coords, header=self.header.coords, gap=gap 105 ) 106 if title: 107 drawBot.textBox(title, self.header.coords) 108 109 def addFooter(self, title: str = None, gap: int = 5) -> None: 110 """ 111 Add a footer `classes.c20_box.KBox` to the page. 112 113 Args: 114 title (optional): Text to write in the footer. 115 gap: Space between footer and body. 116 """ 117 self.footer = KBox(layout.draftBar(self.body.coords, position="bottom")) 118 self.body.coords = layout.draftBody( 119 self.body.coords, footer=self.footer.coords, gap=gap 120 ) 121 if title: 122 drawBot.textBox(title, self.footer.coords) 123 124 def addBleed(self, bleed: int = 7, preview: bool = True) -> None: 125 """ 126 Add crop marks and optional bleed preview. 127 128 Args: 129 bleed: Bleed size. 130 preview: Fill bleed area with black for preview. 131 """ 132 if preview: 133 self.fillBackground((0,)) 134 self.shrink(bleed) 135 self.addCropMarks() 136 if preview: 137 self.fillBackground((1,)) 138 139 self._draftBoxes() 140 141 def debug(self, enabled: bool = True) -> None: 142 """ 143 Debug all child `classes.c20_box.KBox` instances using `lib.layout.xray`. 144 145 Args: 146 enabled: Toggle debug mode. 147 """ 148 if not enabled: 149 return 150 coordsList = [self.frame.coords, self.body.coords] 151 if hasattr(self, "header"): 152 coordsList.append(self.header.coords) 153 if hasattr(self, "footer"): 154 coordsList.append(self.footer.coords) 155 layout.xray(coordsList) 156 157 def _divide(self) -> None: 158 """Draw a spine divider for 2-page PDF view.""" 159 if not self._isSpread or not self.isLeftSide: 160 return 161 162 with drawBot.savedState(): 163 drawBot.fill(None) 164 drawBot.stroke(0, 0.25) 165 drawBot.strokeWidth(3) 166 drawBot.line((self.right, self.bottom), (self.right, self.top)) 167 168 def render(self) -> None: 169 """Render the page to the canvas via `drawBot`.""" 170 drawBot.newPage(*self.dimensions)
8class KPage(KBox): 9 def __init__( 10 self, 11 size: layout.PageSize = "A5", 12 margin: tuple = 5, 13 aside: int = 0, 14 spread: bool = False, 15 render: bool = True, 16 ): 17 """ 18 Extends `classes.c20_box.KBox` to form a page object. 19 20 Args: 21 size: Page size. See `lib.layout.PageSize`. 22 margin: Margin in mm. 23 aside: Width of pagination column. 24 spread: Divide at spine for 2-page PDF view. 25 render: Draw immediately. Otherwise, call `render()` manually. 26 """ 27 super().__init__(size) 28 29 if render: 30 self.render() 31 32 self.aside: int = aside 33 """Width of aside/pagination column.""" 34 self.margin: tuple[int] = layout.mirror(margin) if self.isLeftSide else margin 35 """Margin for the page (mirrored for left side).""" 36 self._isSpread: bool = spread 37 """Used to draw a spine for 2-page PDF view.""" 38 39 self._divide() 40 self._draftBoxes() 41 42 def _draftBoxes(self) -> None: 43 """Set up the frame and body `classes.c20_box.KBox` objects.""" 44 self.frame = KBox(layout.shrink(frame=self.coords, margin=self.margin)) 45 self.body = KBox( 46 layout.shrinkWidth( 47 frame=self.frame.coords, 48 amount=self.aside, 49 origin="right" if self.isRightSide else "left", 50 mode="mm", 51 ) 52 ) 53 54 @property 55 def isLeftSide(self) -> bool: 56 """True if the page is on the left side.""" 57 return layout.pageIsEven() 58 59 @property 60 def isRightSide(self) -> bool: 61 """True if the page is on the right side.""" 62 return not self.isLeftSide 63 64 @property 65 def pageNumber(self) -> int: 66 """The current page number.""" 67 return drawBot.pageCount() 68 69 def fillBackground(self, color: list[int]) -> None: 70 """ 71 Fill the background of the page with a color. 72 73 Args: 74 color: RGB color to fill with. 75 76 Example: 77 ``` 78 page.fillBackground((0.5, 0.5, 0.5)) 79 ``` 80 """ 81 with drawBot.savedState(): 82 drawBot.fill(*color) 83 drawBot.rect(*self.coords) 84 85 self._divide() 86 87 def paginate(self) -> None: 88 """Draw the page number with contextual alignment. Padded to 2 digits.""" 89 drawBot.textBox( 90 str(drawBot.pageCount()).rjust(2, "0"), 91 self.frame.coords, 92 align="left" if self.isRightSide else "right", 93 ) 94 95 def addHeader(self, title: str = None, gap: int = 5) -> None: 96 """ 97 Add a header `classes.c20_box.KBox` to the page. 98 99 Args: 100 title (optional): Text to write in the header. 101 gap: Space between header and body. 102 """ 103 self.header = KBox(layout.draftBar(self.body.coords)) 104 self.body.coords = layout.draftBody( 105 self.body.coords, header=self.header.coords, gap=gap 106 ) 107 if title: 108 drawBot.textBox(title, self.header.coords) 109 110 def addFooter(self, title: str = None, gap: int = 5) -> None: 111 """ 112 Add a footer `classes.c20_box.KBox` to the page. 113 114 Args: 115 title (optional): Text to write in the footer. 116 gap: Space between footer and body. 117 """ 118 self.footer = KBox(layout.draftBar(self.body.coords, position="bottom")) 119 self.body.coords = layout.draftBody( 120 self.body.coords, footer=self.footer.coords, gap=gap 121 ) 122 if title: 123 drawBot.textBox(title, self.footer.coords) 124 125 def addBleed(self, bleed: int = 7, preview: bool = True) -> None: 126 """ 127 Add crop marks and optional bleed preview. 128 129 Args: 130 bleed: Bleed size. 131 preview: Fill bleed area with black for preview. 132 """ 133 if preview: 134 self.fillBackground((0,)) 135 self.shrink(bleed) 136 self.addCropMarks() 137 if preview: 138 self.fillBackground((1,)) 139 140 self._draftBoxes() 141 142 def debug(self, enabled: bool = True) -> None: 143 """ 144 Debug all child `classes.c20_box.KBox` instances using `lib.layout.xray`. 145 146 Args: 147 enabled: Toggle debug mode. 148 """ 149 if not enabled: 150 return 151 coordsList = [self.frame.coords, self.body.coords] 152 if hasattr(self, "header"): 153 coordsList.append(self.header.coords) 154 if hasattr(self, "footer"): 155 coordsList.append(self.footer.coords) 156 layout.xray(coordsList) 157 158 def _divide(self) -> None: 159 """Draw a spine divider for 2-page PDF view.""" 160 if not self._isSpread or not self.isLeftSide: 161 return 162 163 with drawBot.savedState(): 164 drawBot.fill(None) 165 drawBot.stroke(0, 0.25) 166 drawBot.strokeWidth(3) 167 drawBot.line((self.right, self.bottom), (self.right, self.top)) 168 169 def render(self) -> None: 170 """Render the page to the canvas via `drawBot`.""" 171 drawBot.newPage(*self.dimensions)
A layout primitive with coordinates, dimensions and spatial utilities.
KPage( size: None | str | tuple[int, int] = 'A5', margin: tuple = 5, aside: int = 0, spread: bool = False, render: bool = True)
9 def __init__( 10 self, 11 size: layout.PageSize = "A5", 12 margin: tuple = 5, 13 aside: int = 0, 14 spread: bool = False, 15 render: bool = True, 16 ): 17 """ 18 Extends `classes.c20_box.KBox` to form a page object. 19 20 Args: 21 size: Page size. See `lib.layout.PageSize`. 22 margin: Margin in mm. 23 aside: Width of pagination column. 24 spread: Divide at spine for 2-page PDF view. 25 render: Draw immediately. Otherwise, call `render()` manually. 26 """ 27 super().__init__(size) 28 29 if render: 30 self.render() 31 32 self.aside: int = aside 33 """Width of aside/pagination column.""" 34 self.margin: tuple[int] = layout.mirror(margin) if self.isLeftSide else margin 35 """Margin for the page (mirrored for left side).""" 36 self._isSpread: bool = spread 37 """Used to draw a spine for 2-page PDF view.""" 38 39 self._divide() 40 self._draftBoxes()
Extends classes.c20_box.KBox to form a page object.
Arguments:
- size: Page size. See
lib.layout.PageSize. - margin: Margin in mm.
- aside: Width of pagination column.
- spread: Divide at spine for 2-page PDF view.
- render: Draw immediately. Otherwise, call
render()manually.
isLeftSide: bool
54 @property 55 def isLeftSide(self) -> bool: 56 """True if the page is on the left side.""" 57 return layout.pageIsEven()
True if the page is on the left side.
isRightSide: bool
59 @property 60 def isRightSide(self) -> bool: 61 """True if the page is on the right side.""" 62 return not self.isLeftSide
True if the page is on the right side.
pageNumber: int
64 @property 65 def pageNumber(self) -> int: 66 """The current page number.""" 67 return drawBot.pageCount()
The current page number.
def
fillBackground(self, color: list[int]) -> None:
69 def fillBackground(self, color: list[int]) -> None: 70 """ 71 Fill the background of the page with a color. 72 73 Args: 74 color: RGB color to fill with. 75 76 Example: 77 ``` 78 page.fillBackground((0.5, 0.5, 0.5)) 79 ``` 80 """ 81 with drawBot.savedState(): 82 drawBot.fill(*color) 83 drawBot.rect(*self.coords) 84 85 self._divide()
Fill the background of the page with a color.
Arguments:
- color: RGB color to fill with.
Example:
page.fillBackground((0.5, 0.5, 0.5))
def
paginate(self) -> None:
87 def paginate(self) -> None: 88 """Draw the page number with contextual alignment. Padded to 2 digits.""" 89 drawBot.textBox( 90 str(drawBot.pageCount()).rjust(2, "0"), 91 self.frame.coords, 92 align="left" if self.isRightSide else "right", 93 )
Draw the page number with contextual alignment. Padded to 2 digits.
def
addHeader(self, title: str = None, gap: int = 5) -> None:
95 def addHeader(self, title: str = None, gap: int = 5) -> None: 96 """ 97 Add a header `classes.c20_box.KBox` to the page. 98 99 Args: 100 title (optional): Text to write in the header. 101 gap: Space between header and body. 102 """ 103 self.header = KBox(layout.draftBar(self.body.coords)) 104 self.body.coords = layout.draftBody( 105 self.body.coords, header=self.header.coords, gap=gap 106 ) 107 if title: 108 drawBot.textBox(title, self.header.coords)
Add a header classes.c20_box.KBox to the page.
Arguments:
- title (optional): Text to write in the header.
- gap: Space between header and body.
def
addBleed(self, bleed: int = 7, preview: bool = True) -> None:
125 def addBleed(self, bleed: int = 7, preview: bool = True) -> None: 126 """ 127 Add crop marks and optional bleed preview. 128 129 Args: 130 bleed: Bleed size. 131 preview: Fill bleed area with black for preview. 132 """ 133 if preview: 134 self.fillBackground((0,)) 135 self.shrink(bleed) 136 self.addCropMarks() 137 if preview: 138 self.fillBackground((1,)) 139 140 self._draftBoxes()
Add crop marks and optional bleed preview.
Arguments:
- bleed: Bleed size.
- preview: Fill bleed area with black for preview.
def
debug(self, enabled: bool = True) -> None:
142 def debug(self, enabled: bool = True) -> None: 143 """ 144 Debug all child `classes.c20_box.KBox` instances using `lib.layout.xray`. 145 146 Args: 147 enabled: Toggle debug mode. 148 """ 149 if not enabled: 150 return 151 coordsList = [self.frame.coords, self.body.coords] 152 if hasattr(self, "header"): 153 coordsList.append(self.header.coords) 154 if hasattr(self, "footer"): 155 coordsList.append(self.footer.coords) 156 layout.xray(coordsList)
Debug all child classes.c20_box.KBox instances using lib.layout.xray.
Arguments:
- enabled: Toggle debug mode.
def
render(self) -> None:
169 def render(self) -> None: 170 """Render the page to the canvas via `drawBot`.""" 171 drawBot.newPage(*self.dimensions)
Render the page to the canvas via drawBot.