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
 34        self.fString = drawBot.FormattedString(**self.fontProps.calc(), **formattedArgs)
 35        self.pool = pool
 36
 37    def setPool(self, pool: KPool):
 38        """
 39        Sets the word pool for the composer.
 40        """
 41        self.pool = pool
 42        return self
 43
 44    def setOpenTypeFeatures(self, **features: dict[fonts.FontFeature, bool]):
 45        """
 46        Sets OpenType features for the formatted string.
 47        """
 48        drawBot.openTypeFeatures(**features)
 49        self.fString.openTypeFeatures(**features)
 50        return self
 51
 52    def addWord(
 53        self,
 54        width: float,
 55        shape: str = None,
 56        tokens: list[content.CharacterToken] = None,
 57    ):
 58        """
 59        Adds a word from the pool that fits the specified width and optional filters.
 60        """
 61        if not self.pool:
 62            raise AttributeError("No pool set. Use setPool() to set a pool.")
 63
 64        linePool = copy.copy(self.pool)  # ? Create a pool for this line
 65
 66        if shape:
 67            linePool = linePool.filterWithRegex(shape)
 68
 69        if tokens:
 70            linePool = linePool.filterTokens(["nonword"])
 71
 72        word = linePool.getItemByWidth(self.frame.width * width)
 73        # Skip removing from the main pool: Commit June 14, 2025
 74        self._append(word)
 75        return self
 76
 77    def addString(self, string: str):
 78        """
 79        Appends a string to the formatted text.
 80        """
 81        self._append(string)
 82        return self
 83
 84    def _append(self, string: str):
 85        """
 86        Appends a string to the formatted text.
 87        """
 88        # ? Reapply formatted args: spacing needs to be explicit in case it changed
 89        self.fString.append(string, **self.fontProps.calc(), **self.formattedArgs)
 90
 91    def breakLine(self):
 92        """
 93        Inserts a line break in the formatted text.
 94        """
 95        self.fString.append("\n")
 96        return self
 97
 98    def setTab(self, width: float, alignment: Literal["left", "center", "right"]):
 99        """
100        Sets a tab stop at the given width and alignment, then inserts a tab.
101        """
102        self.fString.tabs((self.frame.width * width, alignment))
103        self.fString.append("\t")
104        return self
105
106    def fitForString(self, string: str):
107        """
108        Adjusts font size to fit the string on a single line within the frame. Updates `fontProps` as a side effect.
109        """
110        fs, *_ = fonts.fitBinary(
111            string,
112            self.frame.coords,
113            leading=self.fontProps.leading,
114            letterSpacing=self.fontProps.letterSpacing,
115            precision=1,
116        )
117        self.fontProps = self.fontProps.updateFontSize(fs).apply()
118        return self
119
120    def draw(self):
121        """
122        Draws the composed text into the frame.
123        """
124        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
 35        self.fString = drawBot.FormattedString(**self.fontProps.calc(), **formattedArgs)
 36        self.pool = pool
 37
 38    def setPool(self, pool: KPool):
 39        """
 40        Sets the word pool for the composer.
 41        """
 42        self.pool = pool
 43        return self
 44
 45    def setOpenTypeFeatures(self, **features: dict[fonts.FontFeature, bool]):
 46        """
 47        Sets OpenType features for the formatted string.
 48        """
 49        drawBot.openTypeFeatures(**features)
 50        self.fString.openTypeFeatures(**features)
 51        return self
 52
 53    def addWord(
 54        self,
 55        width: float,
 56        shape: str = None,
 57        tokens: list[content.CharacterToken] = None,
 58    ):
 59        """
 60        Adds a word from the pool that fits the specified width and optional filters.
 61        """
 62        if not self.pool:
 63            raise AttributeError("No pool set. Use setPool() to set a pool.")
 64
 65        linePool = copy.copy(self.pool)  # ? Create a pool for this line
 66
 67        if shape:
 68            linePool = linePool.filterWithRegex(shape)
 69
 70        if tokens:
 71            linePool = linePool.filterTokens(["nonword"])
 72
 73        word = linePool.getItemByWidth(self.frame.width * width)
 74        # Skip removing from the main pool: Commit June 14, 2025
 75        self._append(word)
 76        return self
 77
 78    def addString(self, string: str):
 79        """
 80        Appends a string to the formatted text.
 81        """
 82        self._append(string)
 83        return self
 84
 85    def _append(self, string: str):
 86        """
 87        Appends a string to the formatted text.
 88        """
 89        # ? Reapply formatted args: spacing needs to be explicit in case it changed
 90        self.fString.append(string, **self.fontProps.calc(), **self.formattedArgs)
 91
 92    def breakLine(self):
 93        """
 94        Inserts a line break in the formatted text.
 95        """
 96        self.fString.append("\n")
 97        return self
 98
 99    def setTab(self, width: float, alignment: Literal["left", "center", "right"]):
100        """
101        Sets a tab stop at the given width and alignment, then inserts a tab.
102        """
103        self.fString.tabs((self.frame.width * width, alignment))
104        self.fString.append("\t")
105        return self
106
107    def fitForString(self, string: str):
108        """
109        Adjusts font size to fit the string on a single line within the frame. Updates `fontProps` as a side effect.
110        """
111        fs, *_ = fonts.fitBinary(
112            string,
113            self.frame.coords,
114            leading=self.fontProps.leading,
115            letterSpacing=self.fontProps.letterSpacing,
116            precision=1,
117        )
118        self.fontProps = self.fontProps.updateFontSize(fs).apply()
119        return self
120
121    def draw(self):
122        """
123        Draws the composed text into the frame.
124        """
125        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
35        self.fString = drawBot.FormattedString(**self.fontProps.calc(), **formattedArgs)
36        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.
frame
fontProps
formattedArgs
fString
pool
def setPool(self, pool: classes.c32_pool.KPool):
38    def setPool(self, pool: KPool):
39        """
40        Sets the word pool for the composer.
41        """
42        self.pool = pool
43        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]):
45    def setOpenTypeFeatures(self, **features: dict[fonts.FontFeature, bool]):
46        """
47        Sets OpenType features for the formatted string.
48        """
49        drawBot.openTypeFeatures(**features)
50        self.fString.openTypeFeatures(**features)
51        return self

Sets OpenType features for the formatted string.

def addWord( self, width: float, shape: str = None, tokens: list[typing.Literal['word', 'nonword']] = None):
53    def addWord(
54        self,
55        width: float,
56        shape: str = None,
57        tokens: list[content.CharacterToken] = None,
58    ):
59        """
60        Adds a word from the pool that fits the specified width and optional filters.
61        """
62        if not self.pool:
63            raise AttributeError("No pool set. Use setPool() to set a pool.")
64
65        linePool = copy.copy(self.pool)  # ? Create a pool for this line
66
67        if shape:
68            linePool = linePool.filterWithRegex(shape)
69
70        if tokens:
71            linePool = linePool.filterTokens(["nonword"])
72
73        word = linePool.getItemByWidth(self.frame.width * width)
74        # Skip removing from the main pool: Commit June 14, 2025
75        self._append(word)
76        return self

Adds a word from the pool that fits the specified width and optional filters.

def addString(self, string: str):
78    def addString(self, string: str):
79        """
80        Appends a string to the formatted text.
81        """
82        self._append(string)
83        return self

Appends a string to the formatted text.

def breakLine(self):
92    def breakLine(self):
93        """
94        Inserts a line break in the formatted text.
95        """
96        self.fString.append("\n")
97        return self

Inserts a line break in the formatted text.

def setTab(self, width: float, alignment: Literal['left', 'center', 'right']):
 99    def setTab(self, width: float, alignment: Literal["left", "center", "right"]):
100        """
101        Sets a tab stop at the given width and alignment, then inserts a tab.
102        """
103        self.fString.tabs((self.frame.width * width, alignment))
104        self.fString.append("\t")
105        return self

Sets a tab stop at the given width and alignment, then inserts a tab.

def fitForString(self, string: str):
107    def fitForString(self, string: str):
108        """
109        Adjusts font size to fit the string on a single line within the frame. Updates `fontProps` as a side effect.
110        """
111        fs, *_ = fonts.fitBinary(
112            string,
113            self.frame.coords,
114            leading=self.fontProps.leading,
115            letterSpacing=self.fontProps.letterSpacing,
116            precision=1,
117        )
118        self.fontProps = self.fontProps.updateFontSize(fs).apply()
119        return self

Adjusts font size to fit the string on a single line within the frame. Updates fontProps as a side effect.

def draw(self):
121    def draw(self):
122        """
123        Draws the composed text into the frame.
124        """
125        drawBot.textBox(self.fString, self.frame.coords)

Draws the composed text into the frame.