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.
frame
fontProps
formattedArgs
fString
pool
def setPool(self, pool: classes.c32_pool.KPool):
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.

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

Draws the composed text into the frame.