Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
76 changes: 3 additions & 73 deletions src/kiutils/footprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from os import path

from kiutils.items.zones import Zone
from kiutils.items.brditems import Teardrops, PadStack
from kiutils.items.brditems import Teardrops, PadStack, PadOptions
from kiutils.items.common import Image, Coordinate, Net, Group, Font, EmbeddedFile
from kiutils.items.dimensions import Dimension
from kiutils.items.fpitems import *
Expand Down Expand Up @@ -368,77 +368,6 @@ def _to_sexpr_raw(self):
return expr


@dataclass
class PadOptions:
"""The ``options`` token attributes define the settings used for custom pads. This token is
only used when a custom pad is defined.

Documentation:
https://dev-docs.kicad.org/en/file-formats/sexpr-intro/index.html#_custom_pad_options
"""

clearance: str = "outline"
"""The ``clearance`` token defines the type of clearance used for a custom pad. Valid clearance
types are ``outline`` and ``convexhull``."""

anchor: str = "rect"
"""The ``anchor`` token defines the anchor pad shape of a custom pad. Valid anchor pad shapes
are rect and circle."""

@classmethod
def from_sexpr(cls, exp: list) -> PadOptions:
"""Convert the given S-Expresstion into a PadOptions object

Args:
- exp (list): Part of parsed S-Expression ``(options ...)``

Raises:
- Exception: When given parameter's type is not a list
- Exception: When the first item of the list is not options

Returns:
- PadOptions: Object of the class initialized with the given S-Expression
"""
if not isinstance(exp, list):
raise Exception("Expression does not have the correct type")

if exp[0] != "options":
raise Exception("Expression does not have the correct type")

object = cls()
for item in exp[1:]:
if not isinstance(item, list):
raise ValueError(
f"Expected list property [key, value], got: {item}. Full expression: {exp}"
)
elif item[0] == "clearance":
object.clearance = item[1]
elif item[0] == "anchor":
object.anchor = item[1]
else:
raise ValueError(
f"Unrecognized property key: {item[0]}. Full expression: {item}"
)

return object

def to_sexpr(self, indent: int = 0, newline: bool = False) -> str:
"""Generate the S-Expression representing this object

Args:
- indent (int): Number of whitespaces used to indent the output. Defaults to 0.
- newline (bool): Adds a newline to the end of the output. Defaults to False.

Returns:
- str: S-Expression of this object
"""
raw_expr = self._to_sexpr_raw()
return sexp_to_string(raw_expr)

def _to_sexpr_raw(self):
return ["options", ["clearance", self.clearance], ["anchor", self.anchor]]


@dataclass
class Pad:
"""The ``pad`` token defines a pad in a footprint definition.
Expand Down Expand Up @@ -559,7 +488,8 @@ class Pad:
with a thermal relief. If not set, the footprint thermal_gap setting is used."""

customPadOptions: Optional[PadOptions] = None
"""The optional ``customPadOptions`` token defines the options when a custom pad is defined"""
"""The optional ``customPadOptions`` token defines optional shape-specific parameters used to
refine the pad's geometry or behavior."""

# Documentation seems wrong about primitives here. It seems like its just a list
# of graphical objects, but the docu suggests, besides the list, two other params
Expand Down
80 changes: 79 additions & 1 deletion src/kiutils/items/brditems.py
Original file line number Diff line number Diff line change
Expand Up @@ -2093,6 +2093,77 @@ def _to_sexpr_raw(self):
return expr


@dataclass
class PadOptions:
"""The ``options`` token attributes define the settings used for custom pads. This token is
only used when a custom pad is defined.

Documentation:
https://dev-docs.kicad.org/en/file-formats/sexpr-intro/index.html#_custom_pad_options
"""

clearance: str = "outline"
"""The ``clearance`` token defines the type of clearance used for a custom pad. Valid clearance
types are ``outline`` and ``convexhull``."""

anchor: str = "rect"
"""The ``anchor`` token defines the anchor pad shape of a custom pad. Valid anchor pad shapes
are rect and circle."""

@classmethod
def from_sexpr(cls, exp: list) -> PadOptions:
"""Convert the given S-Expresstion into a PadOptions object

Args:
- exp (list): Part of parsed S-Expression ``(options ...)``

Raises:
- Exception: When given parameter's type is not a list
- Exception: When the first item of the list is not options

Returns:
- PadOptions: Object of the class initialized with the given S-Expression
"""
if not isinstance(exp, list):
raise Exception("Expression does not have the correct type")

if exp[0] != "options":
raise Exception("Expression does not have the correct type")

object = cls()
for item in exp[1:]:
if not isinstance(item, list):
raise ValueError(
f"Expected list property [key, value], got: {item}. Full expression: {exp}"
)
elif item[0] == "clearance":
object.clearance = item[1]
elif item[0] == "anchor":
object.anchor = item[1]
else:
raise ValueError(
f"Unrecognized property key: {item[0]}. Full expression: {item}"
)

return object

def to_sexpr(self, indent: int = 0, newline: bool = False) -> str:
"""Generate the S-Expression representing this object

Args:
- indent (int): Number of whitespaces used to indent the output. Defaults to 0.
- newline (bool): Adds a newline to the end of the output. Defaults to False.

Returns:
- str: S-Expression of this object
"""
raw_expr = self._to_sexpr_raw()
return sexp_to_string(raw_expr)

def _to_sexpr_raw(self):
return ["options", ["clearance", self.clearance], ["anchor", self.anchor]]


@dataclass
class PadStackLayer:
"""The ``padstacklayer`` token defines a pad's geometry and thermal/zoning
Expand Down Expand Up @@ -2137,6 +2208,10 @@ class PadStackLayer:
"""The optional ``primitives`` token defines the drawing objects and options used to define
a custom pad on this layer."""

options: Optional[PadOptions] = None
"""The optional ``options`` token defines optional shape-specific parameters used to
refine the pad's geometry or behavior on this layer."""

@classmethod
def from_sexpr(cls, exp: list) -> PadStackLayer:
"""Convert the given S-Expresstion into a PadStackLayer object
Expand Down Expand Up @@ -2183,6 +2258,8 @@ def from_sexpr(cls, exp: list) -> PadStackLayer:
object.clearance = item[1]
elif item[0] == "zone_connect":
object.zone_connect = item[1]
elif item[0] == "options":
object.options = PadOptions().from_sexpr(item)
elif item[0] == "primitives":
for primitive in item[1:]:
if primitive[0] == "gr_text":
Expand Down Expand Up @@ -2237,7 +2314,8 @@ def _to_sexpr_raw(self):
if self.offset[0] != 0 or self.offset[1] != 0:
expr.append(["offset", self.offset[0], self.offset[1]])

# TODO options
if self.options is not None:
expr.append(self.options._to_sexpr_raw())

if self.primitives is not None and len(self.primitives) > 0:
primitives = ["primitives"]
Expand Down
Loading