Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4a498d7
add missing return type hints
roberto-arista May 8, 2025
0f522e0
fix annotations (with note)
roberto-arista May 8, 2025
8635b99
notes
roberto-arista May 8, 2025
59f950e
ruff
roberto-arista May 8, 2025
fd1c1fe
improve hint
roberto-arista May 8, 2025
ce535a6
avoid issue with circular import
roberto-arista May 8, 2025
4f5b826
defer evalutation of the annotations
roberto-arista May 9, 2025
6cf18ca
sort imports
roberto-arista May 9, 2025
fd607c7
improve hints
roberto-arista May 9, 2025
74cf1bc
format
roberto-arista May 9, 2025
659c70c
add `None`
roberto-arista May 9, 2025
60f5430
Add `Literal` hints
roberto-arista May 9, 2025
14f9c7c
improve hints
roberto-arista May 19, 2025
79400ac
we can import PIL, so we can get this one back
roberto-arista May 19, 2025
4cf0e00
Merge branch 'typemytype:master' into master
roberto-arista Apr 10, 2026
07f3162
avoid issue with circular import
roberto-arista May 8, 2025
9e1daeb
sort imports
roberto-arista May 9, 2025
8fa1461
improve hints
roberto-arista May 19, 2025
be05252
improve docs
roberto-arista Apr 10, 2026
46420f5
improve hints
roberto-arista Apr 10, 2026
3bcfc78
fix test data
typemytype May 15, 2026
03160e2
promote resetVariations to explicit keyword argument
roberto-arista May 18, 2026
aeee478
promote `resetFeatures` to explicit keyword argument
roberto-arista May 18, 2026
924b6c4
Align all examples to use `newPage` instead of `size`
roberto-arista May 18, 2026
839f6ad
Revert "Align all examples to use `newPage` instead of `size`"
roberto-arista May 19, 2026
b2fe5a0
align to the other scripts in the folder
roberto-arista May 19, 2026
d67d2ad
update image
roberto-arista May 19, 2026
8ba36f3
restore print block
roberto-arista May 19, 2026
cb26d22
fixing test
typemytype May 19, 2026
89ec392
fixing test pdf
typemytype May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/content/text/textProperties.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Text Properties
.. autofunction:: drawBot.lineHeight
.. autofunction:: drawBot.tracking
.. autofunction:: drawBot.baselineShift
.. autofunction:: drawBot.openTypeFeatures(frac=True, case=True, ...)
.. autofunction:: drawBot.openTypeFeatures(frac=True, case=True, ..., resetFeatures=False)
.. autofunction:: drawBot.listOpenTypeFeatures
.. autofunction:: drawBot.fontVariations(wdth=0.6, wght=0.1, ...)
.. autofunction:: drawBot.fontVariations(wdth=0.6, wght=0.1, ..., resetVariations=False)
.. autofunction:: drawBot.listFontVariations
.. autofunction:: drawBot.fontNamedInstance
.. autofunction:: drawBot.listNamedInstances
Expand Down
110 changes: 46 additions & 64 deletions drawBot/context/baseContext.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,13 @@ def _curveToOne(self, pt1, pt2, pt3):
"""
self._path.curveToPoint_controlPoint1_controlPoint2_(pt3, pt1, pt2)

def closePath(self):
def closePath(self) -> None:
"""
Close the path.
"""
self._path.closePath()

def beginPath(self, identifier=None):
def beginPath(self, identifier: str | None = None) -> None:
"""
Begin using the path as a so called point pen and start a new subpath.
"""
Expand All @@ -285,9 +285,9 @@ def addPoint(
segmentType: str | None = None,
smooth: bool = False,
name: str | None = None,
identifier=None,
**kwargs,
):
identifier: str | None = None,
**kwargs: Any,
) -> None:
"""
Use the path as a point pen and add a point to the current subpath. `beginPath` must
have been called prior to adding points with `addPoint` calls.
Expand All @@ -303,7 +303,7 @@ def addPoint(
**kwargs,
)

def endPath(self):
def endPath(self) -> None:
"""
End the current subpath. Calling this method has two distinct meanings depending
on the context:
Expand Down Expand Up @@ -603,7 +603,7 @@ def controlPointBounds(self) -> BoundingBox | None:
(x, y), (w, h) = self._path.controlPointBounds()
return x, y, x + w, y + h

def optimizePath(self):
def optimizePath(self) -> None:
count = self._path.elementCount()
if not count or self._path.elementAtIndex_(count - 1) != AppKit.NSMoveToBezierPathElement:
return
Expand All @@ -630,13 +630,13 @@ def copy(self) -> Self:
new.copyContextProperties(self)
return new

def reverse(self):
def reverse(self) -> None:
"""
Reverse the path direction
"""
self._path = self._path.bezierPathByReversingPath()

def appendPath(self, otherPath: Self):
def appendPath(self, otherPath: Self) -> None:
"""
Append a path.
"""
Expand All @@ -653,13 +653,13 @@ def __iadd__(self, other: Self) -> Self:

# transformations

def translate(self, x: float = 0, y: float = 0):
def translate(self, x: float = 0, y: float = 0) -> None:
"""
Translate the path with a given offset.
"""
self.transform((1, 0, 0, 1, x, y))

def rotate(self, angle: float, center: Point = (0, 0)):
def rotate(self, angle: float, center: Point = (0, 0)) -> None:
"""
Rotate the path around the `center` point (which is the origin by default) with a given angle in degrees.
"""
Expand All @@ -668,7 +668,7 @@ def rotate(self, angle: float, center: Point = (0, 0)):
s = math.sin(angle)
self.transform((c, s, -s, c, 0, 0), center)

def scale(self, x: float = 1, y: float | None = None, center: Point = (0, 0)):
def scale(self, x: float = 1, y: float | None = None, center: Point = (0, 0)) -> None:
"""
Scale the path with a given `x` (horizontal scale) and `y` (vertical scale).

Expand All @@ -680,7 +680,7 @@ def scale(self, x: float = 1, y: float | None = None, center: Point = (0, 0)):
y = x
self.transform((x, 0, 0, y, 0, 0), center)

def skew(self, angle1: float, angle2: float = 0, center: Point = (0, 0)):
def skew(self, angle1: float, angle2: float = 0, center: Point = (0, 0)) -> None:
"""
Skew the path with given `angle1` and `angle2`.

Expand All @@ -692,7 +692,7 @@ def skew(self, angle1: float, angle2: float = 0, center: Point = (0, 0)):
angle2 = math.radians(angle2)
self.transform((1, math.tan(angle2), math.tan(angle1), 1, 0, 0), center)

def transform(self, transformMatrix: TransformTuple, center: Point = (0, 0)):
def transform(self, transformMatrix: TransformTuple, center: Point = (0, 0)) -> None:
"""
Transform a path with a transform matrix (xy, xx, yy, yx, x, y).
"""
Expand Down Expand Up @@ -1638,7 +1638,7 @@ def font(
font = getNSFontFromNameOrPath(fontNameOrPath, fontSize or 10, fontNumber)
return getFontName(font)

def fontNumber(self, fontNumber: int):
def fontNumber(self, fontNumber: int) -> None:
self._fontNumber = fontNumber

def fallbackFont(self, fontNameOrPath: SomePath, fontNumber: int = 0) -> str | None:
Expand All @@ -1656,17 +1656,17 @@ def fallbackFont(self, fontNameOrPath: SomePath, fontNumber: int = 0) -> str | N
self._fallbackFontNumber = fontNumber
return fontName

def fallbackFontNumber(self, fontNumber: int):
def fallbackFontNumber(self, fontNumber: int) -> None:
self._fallbackFontNumber = fontNumber

def fontSize(self, fontSize: float):
def fontSize(self, fontSize: float) -> None:
"""
Set the font size in points.
The default `fontSize` is 10pt.
"""
self._fontSize = fontSize

def fill(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1):
def fill(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1) -> None:
"""
Sets the fill color with a `red`, `green`, `blue` and `alpha` value.
Each argument must a value float between 0 and 1.
Expand All @@ -1678,7 +1678,7 @@ def fill(self, r: float | None = None, g: float | None = None, b: float | None =
self._fill = fill
self._cmykFill = None

def stroke(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1):
def stroke(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1) -> None:
"""
Sets the stroke color with a `red`, `green`, `blue` and `alpha` value.
Each argument must a value float between 0 and 1.
Expand All @@ -1697,7 +1697,7 @@ def cmykFill(
y: float | None = None,
k: float | None = None,
alpha: float = 1,
):
) -> None:
"""
Set a fill using a CMYK color before drawing a shape. This is handy if the file is intended for print.

Expand Down Expand Up @@ -1730,39 +1730,39 @@ def cmykStroke(
self._cmykStroke = cmykStroke
self._stroke = None

def strokeWidth(self, strokeWidth: float):
def strokeWidth(self, strokeWidth: float) -> None:
"""
Sets stroke width.
"""
self._strokeWidth = strokeWidth

def align(self, align: str):
def align(self, align: str) -> None:
"""
Sets the text alignment.
Possible `align` values are: `left`, `center` and `right`.
"""
self._align = align

def lineHeight(self, lineHeight: float):
def lineHeight(self, lineHeight: float) -> None:
"""
Set the line height.
"""
self._lineHeight = lineHeight

def tracking(self, tracking: float):
def tracking(self, tracking: float) -> None:
"""
Set the tracking between characters. It adds an absolute number of
points between the characters.
"""
self._tracking = tracking

def baselineShift(self, baselineShift: float):
def baselineShift(self, baselineShift: float) -> None:
"""
Set the shift of the baseline.
"""
self._baselineShift = baselineShift

def underline(self, underline: str | None):
def underline(self, underline: str | None) -> None:
"""
Set the underline value.
Underline must be `single`, `thick`, `double` or `None`.
Expand All @@ -1771,7 +1771,7 @@ def underline(self, underline: str | None):
raise DrawBotError("underline must be %s" % (", ".join(sorted(self._textUnderlineMap.keys()))))
self._underline = underline

def strikethrough(self, strikethrough: str | None):
def strikethrough(self, strikethrough: str | None) -> None:
"""
Set the strikethrough value.
Strikethrough must be `single`, `thick`, `double` or `None`.
Expand All @@ -1780,16 +1780,17 @@ def strikethrough(self, strikethrough: str | None):
raise DrawBotError("strikethrough must be %s" % (", ".join(sorted(self._textstrikethroughMap.keys()))))
self._strikethrough = strikethrough

def url(self, url: str | None):
def url(self, url: str | None) -> None:
"""
set the url value.
url must be a string or `None`
"""
self._url = url

def openTypeFeatures(self, *args: None, **features: bool) -> dict[str, bool]:
def openTypeFeatures(self, *, resetFeatures: bool = False, **features: bool) -> dict[str, bool]:
"""
Enable OpenType features and return the current openType features settings.
You can reset the default values with `openTypeFeatures(resetFeatures=True)`

If no arguments are given `openTypeFeatures()` will just return the current openType features settings.

Expand All @@ -1811,19 +1812,9 @@ def openTypeFeatures(self, *args: None, **features: bool) -> dict[str, bool]:
# draw the formatted string
text(t, (10, 80))
"""
if args and features:
raise DrawBotError("Can't combine positional arguments and keyword arguments")
if args:
if len(args) != 1:
raise DrawBotError("There can only be one positional argument")
if args[0] is not None:
raise DrawBotError("First positional argument can only be None")
warnings.warn("openTypeFeatures(None) is deprecated, use openTypeFeatures(resetFeatures=True) instead.")
if resetFeatures:
self._openTypeFeatures.clear()
else:
if features.pop("resetFeatures", False):
self._openTypeFeatures.clear()
self._openTypeFeatures.update(features)
self._openTypeFeatures.update(features)
return dict(self._openTypeFeatures)

def listOpenTypeFeatures(self, fontNameOrPath: SomePath | None = None, fontNumber: int = 0) -> list[str]:
Expand All @@ -1837,25 +1828,16 @@ def listOpenTypeFeatures(self, fontNameOrPath: SomePath | None = None, fontNumbe
font = getNSFontFromNameOrPath(fontNameOrPath, 10, fontNumber)
return openType.getFeatureTagsForFont(font)

def fontVariations(self, *args: None, **axes: float | bool) -> dict[str, float]:
def fontVariations(self, *, resetVariations: bool = False, **axes: float) -> dict[str, float]:
"""
Pick a variation by axes values and return the current font variations settings.
You can reset the default values with `fontVariations(resetVariations=True)`

If no arguments are given `fontVariations()` will just return the current font variations settings.
"""
if args and axes:
raise DrawBotError("Can't combine positional arguments and keyword arguments")
if args:
if len(args) != 1:
raise DrawBotError("There can only be one positional argument")
if args[0] is not None:
raise DrawBotError("First positional argument can only be None")
warnings.warn("fontVariations(None) is deprecated, use fontVariations(resetVariations=True) instead.")
if resetVariations:
self._fontVariations.clear()
else:
if axes.pop("resetVariations", False):
self._fontVariations.clear()
self._fontVariations.update(axes)
self._fontVariations.update(axes)
defaultVariations = self.listFontVariations()
currentVariation = {axis: data["defaultValue"] for axis, data in defaultVariations.items()}
currentVariation.update(self._fontVariations)
Expand Down Expand Up @@ -1908,7 +1890,7 @@ def listNamedInstances(self, fontNameOrPath: SomePath | None = None, fontNumber:
font = getNSFontFromNameOrPath(fontNameOrPath, 10, fontNumber)
return variation.getNamedInstancesForFont(font)

def tabs(self, tab: tuple[float, str] | None, *tabs: tuple[float, str]):
def tabs(self, tab: tuple[float, str] | None, *tabs: tuple[float, str]) -> None:
"""
Set tabs,tuples of (`float`, `alignment`)
Aligment can be `"left"`, `"center"`, `"right"` or any other character.
Expand All @@ -1932,7 +1914,7 @@ def tabs(self, tab: tuple[float, str] | None, *tabs: tuple[float, str]):
combinedTabs.extend(tabs)
self._tabs = combinedTabs

def indent(self, indent: float):
def indent(self, indent: float) -> None:
"""
Set indent of text left of the paragraph.

Expand Down Expand Up @@ -2005,7 +1987,7 @@ def indent(self, indent: float):
"""
self._indent = indent

def tailIndent(self, indent: float):
def tailIndent(self, indent: float) -> None:
"""
Set indent of text right of the paragraph.

Expand All @@ -2014,19 +1996,19 @@ def tailIndent(self, indent: float):
"""
self._tailIndent = indent

def firstLineIndent(self, indent: float):
def firstLineIndent(self, indent: float) -> None:
"""
Set indent of the text only for the first line.
"""
self._firstLineIndent = indent

def paragraphTopSpacing(self, value: float):
def paragraphTopSpacing(self, value: float) -> None:
"""
set paragraph spacing at the top.
"""
self._paragraphTopSpacing = value

def paragraphBottomSpacing(self, value: float):
def paragraphBottomSpacing(self, value: float) -> None:
"""
set paragraph spacing at the bottom.
"""
Expand Down Expand Up @@ -2729,11 +2711,11 @@ def language(self, language):
def writingDirection(self, direction):
self._state.text.writingDirection(direction)

def openTypeFeatures(self, *args: None, **features: dict[str, bool]) -> dict[str, bool]:
return self._state.text.openTypeFeatures(*args, **features)
def openTypeFeatures(self, *, resetFeatures: bool = False, **features: bool) -> dict[str, bool]:
return self._state.text.openTypeFeatures(resetFeatures=resetFeatures, **features)

def fontVariations(self, *args, **axes):
return self._state.text.fontVariations(*args, **axes)
def fontVariations(self, *, resetVariations: bool = False, **axes: float) -> dict[str, float]:
return self._state.text.fontVariations(resetVariations=resetVariations, **axes)

def fontNamedInstance(self, name, fontNameOrPath):
self._state.text.fontNamedInstance(name, fontNameOrPath)
Expand Down
10 changes: 3 additions & 7 deletions drawBot/context/tools/imageObject.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import AppKit # type: ignore
import Quartz # type: ignore
from math import radians
import os
from math import radians
from typing import Any

import AppKit
from typing import Self

import AppKit # type: ignore
import Quartz # type: ignore

from drawBot.aliases import BoundingBox, Point, RGBAColorTuple, Size, SomePath, TransformTuple
from drawBot.context.baseContext import FormattedString
from drawBot.context.imageContext import _makeBitmapImageRep
from drawBot.misc import DrawBotError, optimizePath

Expand Down
Loading
Loading