classes.c40_text_composer
1from typing import Literal 2import drawBot 3from drawBot import _drawBotDrawingTool as drawBot 4import copy 5 6from lib import content, fonts 7from .c20_box import KBox 8from .c32_pool import KPool 9from datatypes import DFontProps 10 11 12class KTextComposer: 13 """Composes and manages formatted text within a given frame.""" 14 15 def __init__( 16 self, 17 frame: KBox, 18 fontProps: DFontProps, 19 pool: KPool, 20 formattedArgs: dict = None, 21 ): 22 """ 23 Initializes the text composer with a frame, font properties, and a word pool. 24 25 Args: 26 frame: The frame within which the text will be composed. 27 fontProps: The font properties to be applied to the text. 28 pool: The word pool to be used for text composition. 29 formattedArgs: Additional arguments for formatting the text. 30 """ 31 self.frame = frame 32 self.fontProps = fontProps.apply() 33 self.formattedArgs = formattedArgs if formattedArgs else dict() 34 self.fString = drawBot.FormattedString( 35 **self.fontProps.calc(), **self.formattedArgs 36 ) 37 self.pool = pool 38 39 def setPool(self, pool: KPool): 40 """ 41 Sets the word pool for the composer. 42 """ 43 self.pool = pool 44 return self 45 46 def setOpenTypeFeatures(self, **features: dict[fonts.FontFeature, bool]): 47 """ 48 Sets OpenType features for the formatted string. 49 """ 50 drawBot.openTypeFeatures(**features) 51 self.fString.openTypeFeatures(**features) 52 return self 53 54 def addWord( 55 self, 56 width: float, 57 shape: str = None, 58 tokens: list[content.CharacterToken] = None, 59 ): 60 """ 61 Adds a word from the pool that fits the specified width and optional filters. 62 """ 63 if not self.pool: 64 raise AttributeError("No pool set. Use setPool() to set a pool.") 65 66 linePool = copy.copy(self.pool) # ? Create a pool for this line 67 68 if shape: 69 linePool = linePool.filterWithRegex(shape) 70 71 if tokens: 72 linePool = linePool.filterTokens(tokens) 73 74 word = linePool.getItemByWidth(self.frame.width * width) 75 # Skip removing from the main pool: Commit June 14, 2025 76 self._append(word) 77 return self 78 79 def addString(self, string: str): 80 """ 81 Appends a string to the formatted text. 82 """ 83 self._append(string) 84 return self 85 86 def _append(self, string: str): 87 """ 88 Appends a string to the formatted text. 89 """ 90 # ? Reapply formatted args: spacing needs to be explicit in case it changed 91 self.fString.append(string, **self.fontProps.calc(), **self.formattedArgs) 92 93 def breakLine(self): 94 """ 95 Inserts a line break in the formatted text. 96 """ 97 self.fString.append("\n") 98 return self 99 100 def setTab(self, width: float, alignment: Literal["left", "center", "right"]): 101 """ 102 Sets a tab stop at the given width and alignment, then inserts a tab. 103 """ 104 self.fString.tabs((self.frame.width * width, alignment)) 105 self.fString.append("\t") 106 return self 107 108 def fitForString(self, string: str): 109 """ 110 Adjusts font size to fit the string on a single line within the frame. Updates `fontProps` as a side effect. 111 """ 112 fs, *_ = fonts.fitBinary( 113 string, 114 self.frame.coords, 115 leading=self.fontProps.leading, 116 letterSpacing=self.fontProps.letterSpacing, 117 precision=1, 118 ) 119 self.fontProps.updateFontSize(fs).apply() 120 return self 121 122 def draw(self): 123 """ 124 Draws the composed text into the frame. 125 """ 126 drawBot.textBox(self.fString, self.frame.coords)
class
KTextComposer:
13class KTextComposer: 14 """Composes and manages formatted text within a given frame.""" 15 16 def __init__( 17 self, 18 frame: KBox, 19 fontProps: DFontProps, 20 pool: KPool, 21 formattedArgs: dict = None, 22 ): 23 """ 24 Initializes the text composer with a frame, font properties, and a word pool. 25 26 Args: 27 frame: The frame within which the text will be composed. 28 fontProps: The font properties to be applied to the text. 29 pool: The word pool to be used for text composition. 30 formattedArgs: Additional arguments for formatting the text. 31 """ 32 self.frame = frame 33 self.fontProps = fontProps.apply() 34 self.formattedArgs = formattedArgs if formattedArgs else dict() 35 self.fString = drawBot.FormattedString( 36 **self.fontProps.calc(), **self.formattedArgs 37 ) 38 self.pool = pool 39 40 def setPool(self, pool: KPool): 41 """ 42 Sets the word pool for the composer. 43 """ 44 self.pool = pool 45 return self 46 47 def setOpenTypeFeatures(self, **features: dict[fonts.FontFeature, bool]): 48 """ 49 Sets OpenType features for the formatted string. 50 """ 51 drawBot.openTypeFeatures(**features) 52 self.fString.openTypeFeatures(**features) 53 return self 54 55 def addWord( 56 self, 57 width: float, 58 shape: str = None, 59 tokens: list[content.CharacterToken] = None, 60 ): 61 """ 62 Adds a word from the pool that fits the specified width and optional filters. 63 """ 64 if not self.pool: 65 raise AttributeError("No pool set. Use setPool() to set a pool.") 66 67 linePool = copy.copy(self.pool) # ? Create a pool for this line 68 69 if shape: 70 linePool = linePool.filterWithRegex(shape) 71 72 if tokens: 73 linePool = linePool.filterTokens(tokens) 74 75 word = linePool.getItemByWidth(self.frame.width * width) 76 # Skip removing from the main pool: Commit June 14, 2025 77 self._append(word) 78 return self 79 80 def addString(self, string: str): 81 """ 82 Appends a string to the formatted text. 83 """ 84 self._append(string) 85 return self 86 87 def _append(self, string: str): 88 """ 89 Appends a string to the formatted text. 90 """ 91 # ? Reapply formatted args: spacing needs to be explicit in case it changed 92 self.fString.append(string, **self.fontProps.calc(), **self.formattedArgs) 93 94 def breakLine(self): 95 """ 96 Inserts a line break in the formatted text. 97 """ 98 self.fString.append("\n") 99 return self 100 101 def setTab(self, width: float, alignment: Literal["left", "center", "right"]): 102 """ 103 Sets a tab stop at the given width and alignment, then inserts a tab. 104 """ 105 self.fString.tabs((self.frame.width * width, alignment)) 106 self.fString.append("\t") 107 return self 108 109 def fitForString(self, string: str): 110 """ 111 Adjusts font size to fit the string on a single line within the frame. Updates `fontProps` as a side effect. 112 """ 113 fs, *_ = fonts.fitBinary( 114 string, 115 self.frame.coords, 116 leading=self.fontProps.leading, 117 letterSpacing=self.fontProps.letterSpacing, 118 precision=1, 119 ) 120 self.fontProps.updateFontSize(fs).apply() 121 return self 122 123 def draw(self): 124 """ 125 Draws the composed text into the frame. 126 """ 127 drawBot.textBox(self.fString, self.frame.coords)
Composes and manages formatted text within a given frame.
KTextComposer( frame: classes.c20_box.KBox, fontProps: datatypes.data_fontprops.DFontProps, pool: classes.c32_pool.KPool, formattedArgs: dict = None)
16 def __init__( 17 self, 18 frame: KBox, 19 fontProps: DFontProps, 20 pool: KPool, 21 formattedArgs: dict = None, 22 ): 23 """ 24 Initializes the text composer with a frame, font properties, and a word pool. 25 26 Args: 27 frame: The frame within which the text will be composed. 28 fontProps: The font properties to be applied to the text. 29 pool: The word pool to be used for text composition. 30 formattedArgs: Additional arguments for formatting the text. 31 """ 32 self.frame = frame 33 self.fontProps = fontProps.apply() 34 self.formattedArgs = formattedArgs if formattedArgs else dict() 35 self.fString = drawBot.FormattedString( 36 **self.fontProps.calc(), **self.formattedArgs 37 ) 38 self.pool = pool
Initializes the text composer with a frame, font properties, and a word pool.
Arguments:
- frame: The frame within which the text will be composed.
- fontProps: The font properties to be applied to the text.
- pool: The word pool to be used for text composition.
- formattedArgs: Additional arguments for formatting the text.
40 def setPool(self, pool: KPool): 41 """ 42 Sets the word pool for the composer. 43 """ 44 self.pool = pool 45 return self
Sets the word pool for the composer.
def
setOpenTypeFeatures( self, **features: dict[typing.Literal['calt', 'case', 'dlig', 'frac', 'liga', 'kern', 'lnum', 'onum', 'ordn', 'pnum', 'ss01', 'ss02', 'ss03', 'ss04', 'ss05', 'ss06', 'ss07', 'ss08', 'ss09', 'ss10', 'subs', 'sups', 'titl', 'tnum'], bool]):
47 def setOpenTypeFeatures(self, **features: dict[fonts.FontFeature, bool]): 48 """ 49 Sets OpenType features for the formatted string. 50 """ 51 drawBot.openTypeFeatures(**features) 52 self.fString.openTypeFeatures(**features) 53 return self
Sets OpenType features for the formatted string.
def
addWord( self, width: float, shape: str = None, tokens: list[typing.Literal['word', 'nonword']] = None):
55 def addWord( 56 self, 57 width: float, 58 shape: str = None, 59 tokens: list[content.CharacterToken] = None, 60 ): 61 """ 62 Adds a word from the pool that fits the specified width and optional filters. 63 """ 64 if not self.pool: 65 raise AttributeError("No pool set. Use setPool() to set a pool.") 66 67 linePool = copy.copy(self.pool) # ? Create a pool for this line 68 69 if shape: 70 linePool = linePool.filterWithRegex(shape) 71 72 if tokens: 73 linePool = linePool.filterTokens(tokens) 74 75 word = linePool.getItemByWidth(self.frame.width * width) 76 # Skip removing from the main pool: Commit June 14, 2025 77 self._append(word) 78 return self
Adds a word from the pool that fits the specified width and optional filters.
def
addString(self, string: str):
80 def addString(self, string: str): 81 """ 82 Appends a string to the formatted text. 83 """ 84 self._append(string) 85 return self
Appends a string to the formatted text.
def
breakLine(self):
94 def breakLine(self): 95 """ 96 Inserts a line break in the formatted text. 97 """ 98 self.fString.append("\n") 99 return self
Inserts a line break in the formatted text.
def
setTab(self, width: float, alignment: Literal['left', 'center', 'right']):
101 def setTab(self, width: float, alignment: Literal["left", "center", "right"]): 102 """ 103 Sets a tab stop at the given width and alignment, then inserts a tab. 104 """ 105 self.fString.tabs((self.frame.width * width, alignment)) 106 self.fString.append("\t") 107 return self
Sets a tab stop at the given width and alignment, then inserts a tab.
def
fitForString(self, string: str):
109 def fitForString(self, string: str): 110 """ 111 Adjusts font size to fit the string on a single line within the frame. Updates `fontProps` as a side effect. 112 """ 113 fs, *_ = fonts.fitBinary( 114 string, 115 self.frame.coords, 116 leading=self.fontProps.leading, 117 letterSpacing=self.fontProps.letterSpacing, 118 precision=1, 119 ) 120 self.fontProps.updateFontSize(fs).apply() 121 return self
Adjusts font size to fit the string on a single line within the frame. Updates fontProps as a side effect.