Skip to content

Commit 2ea7dd3

Browse files
authored
Merge pull request #111 from mvnmgrx/feature_knockout
Feature: `knockout` token for GrText and FpText elements
2 parents c2d25c1 + 92f30de commit 2ea7dd3

File tree

6 files changed

+103
-6
lines changed

6 files changed

+103
-6
lines changed

Diff for: src/kiutils/items/fpitems.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ class FpText():
4848
layer: str = "F.Cu"
4949
"""The ``layer`` token defines the canonical layer the text resides on"""
5050

51+
knockout: bool = False
52+
"""The ``knockout`` token defines if the text is inverted (means transparent text and colored
53+
background insted of colored text and transparent background)"""
54+
5155
hide: bool = False
5256
"""The optional ``hide`` token, defines if the text is hidden"""
5357

@@ -91,7 +95,11 @@ def from_sexpr(cls, exp: list) -> FpText:
9195
if item == 'hide': object.hide = True
9296
continue
9397
if item[0] == 'at': object.position = Position().from_sexpr(item)
94-
if item[0] == 'layer': object.layer = item[1]
98+
if item[0] == 'layer':
99+
object.layer = item[1]
100+
if(len(item) > 2):
101+
if(item[2] == "knockout"):
102+
object.knockout = True
95103
if item[0] == 'effects': object.effects = Effects().from_sexpr(item)
96104
if item[0] == 'tstamp': object.tstamp = item[1]
97105
if item[0] == 'render_cache': object.renderCache = RenderCache.from_sexpr(item)
@@ -113,8 +121,9 @@ def to_sexpr(self, indent: int = 2, newline: bool = True) -> str:
113121
hide = ' hide' if self.hide else ''
114122
unlocked = ' unlocked' if self.position.unlocked else ''
115123
posA = f' {self.position.angle}' if self.position.angle is not None else ''
124+
ko = ' knockout' if self.knockout else ''
116125

117-
expression = f'{indents}(fp_text {self.type} "{dequote(self.text)}" (at {self.position.X} {self.position.Y}{posA}{unlocked}) (layer "{dequote(self.layer)}"){hide}\n'
126+
expression = f'{indents}(fp_text {self.type} "{dequote(self.text)}" (at {self.position.X} {self.position.Y}{posA}{unlocked}) (layer "{dequote(self.layer)}"{ko}){hide}\n'
118127
expression += f'{indents} {self.effects.to_sexpr()}'
119128
if self.tstamp is not None:
120129
expression += f'{indents} (tstamp {self.tstamp})\n'

Diff for: src/kiutils/items/gritems.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,13 @@ class GrText():
3434
text: str = ""
3535
"""The ``text`` attribute is a string that defines the text"""
3636

37+
knockout: bool = False
38+
"""The ``knockout`` token defines if the text is inverted (means transparent text and colored
39+
background insted of colored text and transparent background)"""
40+
3741
position: Position = field(default_factory=lambda: Position())
38-
"""The ``position`` defines the X and Y position coordinates and optional orientation angle of the text"""
42+
"""The ``position`` defines the X and Y position coordinates and optional orientation angle of
43+
the text"""
3944

4045
layer: Optional[str] = None
4146
"""The ``layer`` token defines the canonical layer the text resides on"""
@@ -82,7 +87,11 @@ def from_sexpr(cls, exp: list) -> GrText:
8287
if item == 'locked': object.locked = True
8388
continue
8489
if item[0] == 'at': object.position = Position().from_sexpr(item)
85-
if item[0] == 'layer': object.layer = item[1]
90+
if item[0] == 'layer':
91+
object.layer = item[1]
92+
if(len(item) > 2):
93+
if(item[2] == "knockout"):
94+
object.knockout = True
8695
if item[0] == 'effects': object.effects = Effects().from_sexpr(item)
8796
if item[0] == 'tstamp': object.tstamp = item[1]
8897
if item[0] == 'render_cache': object.renderCache = RenderCache.from_sexpr(item)
@@ -101,8 +110,9 @@ def to_sexpr(self, indent: int = 2, newline: bool = True) -> str:
101110
indents = ' '*indent
102111
endline = '\n' if newline else ''
103112

113+
ko = ' knockout' if self.knockout else ''
104114
posA = f' {self.position.angle}' if self.position.angle is not None else ''
105-
layer = f' (layer "{dequote(self.layer)}")' if self.layer is not None else ''
115+
layer = f' (layer "{dequote(self.layer)}"{ko})' if self.layer is not None else ''
106116
tstamp = f' (tstamp {self.tstamp})' if self.tstamp is not None else ''
107117
locked = f' locked' if self.locked else ''
108118

Diff for: tests/test_board.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,11 @@ def test_textsWithRenderCaches(self):
133133
self.testData.compareToTestFile = True
134134
self.testData.pathToTestFile = path.join(BOARD_BASE, 'since_v7', 'test_textsWithRenderCaches')
135135
board = Board().from_file(self.testData.pathToTestFile)
136-
self.assertTrue(to_file_and_compare(board, self.testData))
136+
self.assertTrue(to_file_and_compare(board, self.testData))
137+
138+
def test_testKnockout(self):
139+
"""Tests the ``knockout`` token of a graphical text"""
140+
self.testData.compareToTestFile = True
141+
self.testData.pathToTestFile = path.join(BOARD_BASE, 'since_v7', 'test_textKnockout')
142+
footprint = Board().from_file(self.testData.pathToTestFile)
143+
self.assertTrue(to_file_and_compare(footprint, self.testData))

Diff for: tests/test_footprint.py

+6
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,9 @@ def test_netTiePadGroups(self):
175175
footprint = Footprint().from_file(self.testData.pathToTestFile)
176176
self.assertTrue(to_file_and_compare(footprint, self.testData))
177177

178+
def test_testKnockout(self):
179+
"""Tests the ``knockout`` token of a footprint text"""
180+
self.testData.compareToTestFile = True
181+
self.testData.pathToTestFile = path.join(FOOTPRINT_BASE, 'since_v7', 'test_textKnockout')
182+
footprint = Footprint().from_file(self.testData.pathToTestFile)
183+
self.assertTrue(to_file_and_compare(footprint, self.testData))

Diff for: tests/testdata/board/since_v7/test_textKnockout

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
(kicad_pcb (version 20221018) (generator pcbnew)
2+
3+
(general
4+
(thickness 1.6)
5+
)
6+
7+
(paper "A4")
8+
(layers
9+
(0 "F.Cu" signal)
10+
(31 "B.Cu" signal)
11+
(32 "B.Adhes" user "B.Adhesive")
12+
(33 "F.Adhes" user "F.Adhesive")
13+
(34 "B.Paste" user)
14+
(35 "F.Paste" user)
15+
(36 "B.SilkS" user "B.Silkscreen")
16+
(37 "F.SilkS" user "F.Silkscreen")
17+
(38 "B.Mask" user)
18+
(39 "F.Mask" user)
19+
(40 "Dwgs.User" user "User.Drawings")
20+
(41 "Cmts.User" user "User.Comments")
21+
(42 "Eco1.User" user "User.Eco1")
22+
(43 "Eco2.User" user "User.Eco2")
23+
(44 "Edge.Cuts" user)
24+
(45 "Margin" user)
25+
(46 "B.CrtYd" user "B.Courtyard")
26+
(47 "F.CrtYd" user "F.Courtyard")
27+
(48 "B.Fab" user)
28+
(49 "F.Fab" user)
29+
(50 "User.1" user)
30+
(51 "User.2" user)
31+
(52 "User.3" user)
32+
(53 "User.4" user)
33+
(54 "User.5" user)
34+
(55 "User.6" user)
35+
(56 "User.7" user)
36+
(57 "User.8" user)
37+
(58 "User.9" user)
38+
)
39+
40+
(setup
41+
(pad_to_mask_clearance 0)
42+
)
43+
44+
(net 0 "")
45+
46+
(gr_text "test" (at 168.42 92.81) (layer "F.Cu" knockout) (tstamp 37d6611e-bb8c-49f5-bc61-44562605f28f)
47+
(effects (font (size 1.5 1.5) (thickness 0.3) bold) (justify left bottom))
48+
)
49+
50+
)

Diff for: tests/testdata/footprint/since_v7/test_textKnockout

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(footprint "CP_Elec_3x5.4" (version 20221018) (generator pcbnew)
2+
(layer "F.Cu")
3+
(tedit 65bd7f8d)
4+
(descr "SMD capacitor, aluminum electrolytic, Nichicon, 3.0x5.4mm")
5+
(tags "capacitor electrolytic")
6+
(attr smd)
7+
(fp_text reference "REF**" (at 0 -2.7) (layer "F.SilkS" knockout)
8+
(effects (font (size 1 1) (thickness 0.15)))
9+
(tstamp 44d2ce4a-f555-443e-872b-4f08845b4e47)
10+
)
11+
(fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab")
12+
(effects (font (size 0.6 0.6) (thickness 0.09)))
13+
(tstamp b78f3199-5a9c-4fe8-bce1-484a2ec30068)
14+
)
15+
)

0 commit comments

Comments
 (0)