datatypes.data_fontprops
1from typing import List, Literal, NamedTuple 2import drawBot 3 4from lib import helpers, fonts 5from classes import KFont 6 7# TODO: Add RGB/CMYK fill property 8 9 10class DFontProps(NamedTuple): 11 """Data structure for font properties used in DrawBot.""" 12 13 fontSize: int = 24 14 """The font size in points.""" 15 16 leading: float = 1.25 17 """The leading (line spacing) multiplier.""" 18 19 letterSpacing: int = 0 20 """Relative letter spacing unit, behaves similar to Adobe.""" 21 22 fontData: KFont | list[KFont] = None 23 """The font data or list of font data.""" 24 25 align: str = None 26 """Text alignment option.""" 27 28 openType: fonts.FontFeature | list[fonts.FontFeature] = None 29 """OpenType font features.""" 30 31 @property 32 def lineHeight(self): 33 """The calculated line height. 34 35 Returns: 36 The product of fontSize and leading, or None if fontSize undefined. 37 """ 38 try: 39 return self.fontSize * self.leading 40 except Exception: 41 return 42 43 @property 44 def tracking(self): 45 """The absolute tracking value, scales with fontSize. 46 47 Returns: 48 The calculated tracking value, or None if calculation fails. 49 """ 50 try: 51 return self.letterSpacing * (self.fontSize / 1000) 52 except Exception: 53 return 54 55 @property 56 def fontPath(self): 57 """The file path of the font. 58 59 Returns: 60 The path to the font file, or the fontData if path is unavailable. 61 """ 62 try: 63 return self.fontData.path 64 except Exception: 65 return self.fontData 66 67 @property 68 def isSingleFont(self) -> bool: 69 """Whether fontData is a single font. 70 71 Returns: 72 True if fontData is a string or KFont instance, False otherwise. 73 """ 74 return isinstance(self.fontData, (str, KFont)) 75 76 @property 77 def openTypeFeatures(self): 78 """OpenType features as a dictionary. 79 80 Returns: 81 Dictionary of OpenType features set to True, or None if unavailable. 82 """ 83 try: 84 return {key: True for key in helpers.coerceList(self.openType)} 85 except Exception: 86 pass 87 88 def getArgs(self, clean=False, pick: list[str] = None) -> dict: 89 """ 90 Get properties as a dictionary. 91 92 Args: 93 clean: If True, remove falsy properties. 94 pick: List of property keys to include. 95 96 Returns: 97 Dictionary of font properties. 98 """ 99 asDict = self._asdict() 100 asDict["lineHeight"] = self.lineHeight 101 asDict["tracking"] = self.tracking 102 asDict["openTypeFeatures"] = self.openTypeFeatures 103 104 if self.align: 105 asDict["align"] = self.align 106 107 if self.isSingleFont: 108 asDict["font"] = self.fontPath 109 110 if pick: 111 asDict = helpers.pick(asDict, pick) 112 113 if clean: 114 return helpers.omitBy(asDict) 115 else: 116 return asDict 117 118 def calc(self, clean=True) -> dict: 119 """ 120 Calculate keyword arguments for FormattedString(). 121 122 Args: 123 clean: If True, remove falsy properties. 124 125 Returns: 126 Dictionary of keyword arguments for FormattedString(). 127 """ 128 129 return self.getArgs( 130 clean=clean, 131 pick=[ 132 "font", 133 "fontSize", 134 "lineHeight", 135 "tracking", 136 "align", 137 "openTypeFeatures", 138 ], 139 ) 140 141 def activateFont(self): 142 """ 143 Set the font for DrawBot. 144 145 Returns: 146 The current instance. 147 """ 148 if self.isSingleFont: 149 drawBot.font(self.fontPath) 150 return self 151 152 def apply(self): 153 """ 154 Set DrawBot properties for the current font settings. 155 156 Returns: 157 The current instance. 158 """ 159 drawBot.fontSize(self.fontSize) 160 drawBot.lineHeight(self.lineHeight) 161 drawBot.tracking(self.tracking) 162 163 self.activateFont() 164 165 if self.openTypeFeatures: 166 drawBot.openTypeFeatures(**self.openTypeFeatures) 167 else: 168 drawBot.openTypeFeatures(resetFeatures=True) 169 170 return self 171 172 def describe(self, format: Literal["string", "list"] = "string"): 173 """ 174 Return human-friendly font properties. 175 176 Args: 177 format: Return as 'str' or 'list[str]'. 178 179 Returns: 180 Human-readable font properties. 181 """ 182 183 props: List[float | int] = [self.fontSize] 184 lh, t = self.lineHeight, self.letterSpacing 185 186 if lh and lh != self.fontSize: 187 props.append(lh) 188 if t: 189 props.append(t) 190 191 rounded = [str(round(p)) for p in props] 192 return rounded if format == "list" else " ".join(rounded) 193 194 def updateFont(self, value: KFont): 195 """ 196 Update font and return a new instance (since NamedTuple is immutable). 197 198 Args: 199 value: The new font. 200 201 Example: 202 `props = props.updateFont(newFont)` 203 """ 204 return self._replace(fontData=value) 205 206 def updateFontSize(self, value: int): 207 """ 208 Update fontSize and return a new instance (since NamedTuple is immutable). 209 210 Args: 211 value: The new font size. 212 213 Example: 214 `props = props.updateFontSize(12)` 215 216 Returns: 217 New instance with updated fontSize. 218 """ 219 return self._replace(fontSize=value)
11class DFontProps(NamedTuple): 12 """Data structure for font properties used in DrawBot.""" 13 14 fontSize: int = 24 15 """The font size in points.""" 16 17 leading: float = 1.25 18 """The leading (line spacing) multiplier.""" 19 20 letterSpacing: int = 0 21 """Relative letter spacing unit, behaves similar to Adobe.""" 22 23 fontData: KFont | list[KFont] = None 24 """The font data or list of font data.""" 25 26 align: str = None 27 """Text alignment option.""" 28 29 openType: fonts.FontFeature | list[fonts.FontFeature] = None 30 """OpenType font features.""" 31 32 @property 33 def lineHeight(self): 34 """The calculated line height. 35 36 Returns: 37 The product of fontSize and leading, or None if fontSize undefined. 38 """ 39 try: 40 return self.fontSize * self.leading 41 except Exception: 42 return 43 44 @property 45 def tracking(self): 46 """The absolute tracking value, scales with fontSize. 47 48 Returns: 49 The calculated tracking value, or None if calculation fails. 50 """ 51 try: 52 return self.letterSpacing * (self.fontSize / 1000) 53 except Exception: 54 return 55 56 @property 57 def fontPath(self): 58 """The file path of the font. 59 60 Returns: 61 The path to the font file, or the fontData if path is unavailable. 62 """ 63 try: 64 return self.fontData.path 65 except Exception: 66 return self.fontData 67 68 @property 69 def isSingleFont(self) -> bool: 70 """Whether fontData is a single font. 71 72 Returns: 73 True if fontData is a string or KFont instance, False otherwise. 74 """ 75 return isinstance(self.fontData, (str, KFont)) 76 77 @property 78 def openTypeFeatures(self): 79 """OpenType features as a dictionary. 80 81 Returns: 82 Dictionary of OpenType features set to True, or None if unavailable. 83 """ 84 try: 85 return {key: True for key in helpers.coerceList(self.openType)} 86 except Exception: 87 pass 88 89 def getArgs(self, clean=False, pick: list[str] = None) -> dict: 90 """ 91 Get properties as a dictionary. 92 93 Args: 94 clean: If True, remove falsy properties. 95 pick: List of property keys to include. 96 97 Returns: 98 Dictionary of font properties. 99 """ 100 asDict = self._asdict() 101 asDict["lineHeight"] = self.lineHeight 102 asDict["tracking"] = self.tracking 103 asDict["openTypeFeatures"] = self.openTypeFeatures 104 105 if self.align: 106 asDict["align"] = self.align 107 108 if self.isSingleFont: 109 asDict["font"] = self.fontPath 110 111 if pick: 112 asDict = helpers.pick(asDict, pick) 113 114 if clean: 115 return helpers.omitBy(asDict) 116 else: 117 return asDict 118 119 def calc(self, clean=True) -> dict: 120 """ 121 Calculate keyword arguments for FormattedString(). 122 123 Args: 124 clean: If True, remove falsy properties. 125 126 Returns: 127 Dictionary of keyword arguments for FormattedString(). 128 """ 129 130 return self.getArgs( 131 clean=clean, 132 pick=[ 133 "font", 134 "fontSize", 135 "lineHeight", 136 "tracking", 137 "align", 138 "openTypeFeatures", 139 ], 140 ) 141 142 def activateFont(self): 143 """ 144 Set the font for DrawBot. 145 146 Returns: 147 The current instance. 148 """ 149 if self.isSingleFont: 150 drawBot.font(self.fontPath) 151 return self 152 153 def apply(self): 154 """ 155 Set DrawBot properties for the current font settings. 156 157 Returns: 158 The current instance. 159 """ 160 drawBot.fontSize(self.fontSize) 161 drawBot.lineHeight(self.lineHeight) 162 drawBot.tracking(self.tracking) 163 164 self.activateFont() 165 166 if self.openTypeFeatures: 167 drawBot.openTypeFeatures(**self.openTypeFeatures) 168 else: 169 drawBot.openTypeFeatures(resetFeatures=True) 170 171 return self 172 173 def describe(self, format: Literal["string", "list"] = "string"): 174 """ 175 Return human-friendly font properties. 176 177 Args: 178 format: Return as 'str' or 'list[str]'. 179 180 Returns: 181 Human-readable font properties. 182 """ 183 184 props: List[float | int] = [self.fontSize] 185 lh, t = self.lineHeight, self.letterSpacing 186 187 if lh and lh != self.fontSize: 188 props.append(lh) 189 if t: 190 props.append(t) 191 192 rounded = [str(round(p)) for p in props] 193 return rounded if format == "list" else " ".join(rounded) 194 195 def updateFont(self, value: KFont): 196 """ 197 Update font and return a new instance (since NamedTuple is immutable). 198 199 Args: 200 value: The new font. 201 202 Example: 203 `props = props.updateFont(newFont)` 204 """ 205 return self._replace(fontData=value) 206 207 def updateFontSize(self, value: int): 208 """ 209 Update fontSize and return a new instance (since NamedTuple is immutable). 210 211 Args: 212 value: The new font size. 213 214 Example: 215 `props = props.updateFontSize(12)` 216 217 Returns: 218 New instance with updated fontSize. 219 """ 220 return self._replace(fontSize=value)
Data structure for font properties used in DrawBot.
Create new instance of DFontProps(fontSize, leading, letterSpacing, fontData, align, openType)
OpenType font features.
32 @property 33 def lineHeight(self): 34 """The calculated line height. 35 36 Returns: 37 The product of fontSize and leading, or None if fontSize undefined. 38 """ 39 try: 40 return self.fontSize * self.leading 41 except Exception: 42 return
The calculated line height.
Returns:
The product of fontSize and leading, or None if fontSize undefined.
44 @property 45 def tracking(self): 46 """The absolute tracking value, scales with fontSize. 47 48 Returns: 49 The calculated tracking value, or None if calculation fails. 50 """ 51 try: 52 return self.letterSpacing * (self.fontSize / 1000) 53 except Exception: 54 return
The absolute tracking value, scales with fontSize.
Returns:
The calculated tracking value, or None if calculation fails.
56 @property 57 def fontPath(self): 58 """The file path of the font. 59 60 Returns: 61 The path to the font file, or the fontData if path is unavailable. 62 """ 63 try: 64 return self.fontData.path 65 except Exception: 66 return self.fontData
The file path of the font.
Returns:
The path to the font file, or the fontData if path is unavailable.
68 @property 69 def isSingleFont(self) -> bool: 70 """Whether fontData is a single font. 71 72 Returns: 73 True if fontData is a string or KFont instance, False otherwise. 74 """ 75 return isinstance(self.fontData, (str, KFont))
Whether fontData is a single font.
Returns:
True if fontData is a string or KFont instance, False otherwise.
77 @property 78 def openTypeFeatures(self): 79 """OpenType features as a dictionary. 80 81 Returns: 82 Dictionary of OpenType features set to True, or None if unavailable. 83 """ 84 try: 85 return {key: True for key in helpers.coerceList(self.openType)} 86 except Exception: 87 pass
OpenType features as a dictionary.
Returns:
Dictionary of OpenType features set to True, or None if unavailable.
89 def getArgs(self, clean=False, pick: list[str] = None) -> dict: 90 """ 91 Get properties as a dictionary. 92 93 Args: 94 clean: If True, remove falsy properties. 95 pick: List of property keys to include. 96 97 Returns: 98 Dictionary of font properties. 99 """ 100 asDict = self._asdict() 101 asDict["lineHeight"] = self.lineHeight 102 asDict["tracking"] = self.tracking 103 asDict["openTypeFeatures"] = self.openTypeFeatures 104 105 if self.align: 106 asDict["align"] = self.align 107 108 if self.isSingleFont: 109 asDict["font"] = self.fontPath 110 111 if pick: 112 asDict = helpers.pick(asDict, pick) 113 114 if clean: 115 return helpers.omitBy(asDict) 116 else: 117 return asDict
Get properties as a dictionary.
Arguments:
- clean: If True, remove falsy properties.
- pick: List of property keys to include.
Returns:
Dictionary of font properties.
119 def calc(self, clean=True) -> dict: 120 """ 121 Calculate keyword arguments for FormattedString(). 122 123 Args: 124 clean: If True, remove falsy properties. 125 126 Returns: 127 Dictionary of keyword arguments for FormattedString(). 128 """ 129 130 return self.getArgs( 131 clean=clean, 132 pick=[ 133 "font", 134 "fontSize", 135 "lineHeight", 136 "tracking", 137 "align", 138 "openTypeFeatures", 139 ], 140 )
Calculate keyword arguments for FormattedString().
Arguments:
- clean: If True, remove falsy properties.
Returns:
Dictionary of keyword arguments for FormattedString().
142 def activateFont(self): 143 """ 144 Set the font for DrawBot. 145 146 Returns: 147 The current instance. 148 """ 149 if self.isSingleFont: 150 drawBot.font(self.fontPath) 151 return self
Set the font for DrawBot.
Returns:
The current instance.
153 def apply(self): 154 """ 155 Set DrawBot properties for the current font settings. 156 157 Returns: 158 The current instance. 159 """ 160 drawBot.fontSize(self.fontSize) 161 drawBot.lineHeight(self.lineHeight) 162 drawBot.tracking(self.tracking) 163 164 self.activateFont() 165 166 if self.openTypeFeatures: 167 drawBot.openTypeFeatures(**self.openTypeFeatures) 168 else: 169 drawBot.openTypeFeatures(resetFeatures=True) 170 171 return self
Set DrawBot properties for the current font settings.
Returns:
The current instance.
173 def describe(self, format: Literal["string", "list"] = "string"): 174 """ 175 Return human-friendly font properties. 176 177 Args: 178 format: Return as 'str' or 'list[str]'. 179 180 Returns: 181 Human-readable font properties. 182 """ 183 184 props: List[float | int] = [self.fontSize] 185 lh, t = self.lineHeight, self.letterSpacing 186 187 if lh and lh != self.fontSize: 188 props.append(lh) 189 if t: 190 props.append(t) 191 192 rounded = [str(round(p)) for p in props] 193 return rounded if format == "list" else " ".join(rounded)
Return human-friendly font properties.
Arguments:
- format: Return as 'str' or 'list[str]'.
Returns:
Human-readable font properties.
195 def updateFont(self, value: KFont): 196 """ 197 Update font and return a new instance (since NamedTuple is immutable). 198 199 Args: 200 value: The new font. 201 202 Example: 203 `props = props.updateFont(newFont)` 204 """ 205 return self._replace(fontData=value)
Update font and return a new instance (since NamedTuple is immutable).
Arguments:
- value: The new font.
Example:
props = props.updateFont(newFont)
207 def updateFontSize(self, value: int): 208 """ 209 Update fontSize and return a new instance (since NamedTuple is immutable). 210 211 Args: 212 value: The new font size. 213 214 Example: 215 `props = props.updateFontSize(12)` 216 217 Returns: 218 New instance with updated fontSize. 219 """ 220 return self._replace(fontSize=value)
Update fontSize and return a new instance (since NamedTuple is immutable).
Arguments:
- value: The new font size.
Example:
props = props.updateFontSize(12)
Returns:
New instance with updated fontSize.