One more check on valid display which is known to be in the startup
[xcircuit.git] / lib / tcl / symbol.tcl
blob9198205c16384740978553c47fdd38f77940f507
1 #---------------------------------------------------------------------------
2 # symbol.tcl ---
4 # xcircuit Tcl script for generating
5 # a canonical circuit symbol
7 # Tim Edwards 12/1/05 for MultiGiG
8 #---------------------------------------------------------------------------
10 #---------------------------------------------------------------------------
11 # Get the info label line declaring the text subcircuit, if one exists.
12 #---------------------------------------------------------------------------
14 proc xcircuit::getsubckttext {name} {
15 global XCOps
17 set curhandle [object handle]
18 set handle [page handle $name]
19 if {$curhandle != $handle} {schematic goto}
21 set pageparts [object $handle parts]
23 set itext {}
24 foreach j $pageparts {
25 set etype [element $j type]
26 if {$etype == "Label"} {
27 set ltype [label $j type]
28 if {$ltype == "info"} {
29 set itext [label $j text]
30 if {[string first ".subckt" $itext] >= 0} {
31 if {$curhandle != $handle} {symbol goto}
32 return $itext
37 deselect selected
38 return ""
41 #---------------------------------------------------------------------------
42 # Create a matching symbol for a subcircuit page or SPICE file.
44 # This is a replacement for the procedure makesymbol in wrapper.tcl.
45 # We make a sub-widget to list, change, and reorder the symbol pins,
46 # similar to the "addliblist" procedure in wrapper.tcl
48 # Modified 1/5/06: If "filename" is non-null, then it points to a SPICE
49 # netlist containing a subcircuit. A symbol is made to correspond to the
50 # subcircuit definition, with a link to include the file.
52 # Modified 1/7/06: If "orderedpins" is non-null, then it contains the
53 # list of pins in proper order.
54 #---------------------------------------------------------------------------
56 proc xcircuit::makesymbol {{filename ""} {orderedpins ""}} {
57 global XCOps
59 config suspend true ;# suspend graphics and change count
61 set techname [.makesymbol.techself.techselect cget -text]
62 set symbolname [.makesymbol.textent.txt get]
63 if {[string length $symbolname] == 0} {
64 set symbolname [page label]
65 if {[string length $symbolname] == 0 || [string first "Page " $symbolname] >= 0} {
66 puts stderr "Symbol/Schematic has no name!"
67 consoleup
68 return
72 if {[string first :: $symbolname] >= 0} { ;# symbolname has tech name embedded
73 set techname ""
74 } elseif {[string first ( $techname] >= 0} { ;# "(user)" specified
75 set techname "::"
76 } elseif {[string first :: $techname] < 0} {
77 set techname "${techname}::"
80 # If "filename" is specified then we have a netlist, not a schematic.
81 # Therefore, create an object but don't use xcircuit::symbol
83 if {$filename == ""} {
84 deselect selected
85 xcircuit::symbol make ${techname}${symbolname} $XCOps(library);
86 set schematicname [schematic get]
87 set noschem 0
88 } else {
89 set schematicname $symbolname
90 set noschem 1
93 set pinspace 64
94 set halfspace [expr $pinspace / 2]
95 set qtrspace [expr $pinspace / 4]
97 # remove the old pin labels
99 set oldpinlabels [object parts]
100 foreach j $oldpinlabels {
101 delete $j
103 set leftpins [.makesymbol.pinself.left.list index end]
104 set toppins [.makesymbol.pinself.top.list index end]
105 set rightpins [.makesymbol.pinself.right.list index end]
106 set botpins [.makesymbol.pinself.bottom.list index end]
108 set hpins $leftpins
109 if {$rightpins > $leftpins} {set hpins $rightpins}
110 set vpins $toppins
111 if {$botpins > $toppins} {set vpins $botpins}
113 set boxwidth [expr ($vpins + 1) * $pinspace]
114 set boxheight [expr ($hpins + 1) * $pinspace]
116 set hwidth [expr $boxwidth / 2]
117 if {$hwidth < 256} {set hwidth 256}
118 set hheight [expr $boxheight / 2]
119 if {$hheight < 256} {set hheight 256}
121 set sbox [polygon make box "-$hwidth -$hheight" "$hwidth $hheight"]
122 set pinlabels {}
124 # If we didn't make a symbol using xcircuit::symbol, now is the time
125 # to generate the object.
127 if {$noschem == 1} {
128 select $sbox
129 set handle [object make ${techname}${symbolname} $XCOps(library)]
130 push $handle
133 # Ordered right->left->bottom->top, on logical grounds.
135 set x [expr $hwidth + $qtrspace]
136 set y [expr -($rightpins - 1) * $halfspace]
137 for {set j 0} {$j < $rightpins} {incr j} {
138 set tabx [expr $x - $qtrspace]
139 polygon make 2 "$x $y" "$tabx $y"
140 set pintext [.makesymbol.pinself.right.list get $j]
141 lappend pinlabels $pintext
142 set tlab [label make pin "$pintext" "$x $y"]
143 label $tlab anchor left
144 label $tlab anchor middle
145 set nlab [element $tlab copy relative "-$halfspace 0"]
146 label $nlab type normal
147 label $nlab anchor right
148 incr y $pinspace
149 deselect selected
151 set x [expr -$hwidth - $qtrspace]
152 set y [expr -($leftpins - 1) * $halfspace]
153 for {set j 0} {$j < $leftpins} {incr j} {
154 set tabx [expr $x + $qtrspace]
155 polygon make 2 "$x $y" "$tabx $y"
156 set pintext [.makesymbol.pinself.left.list get $j]
157 lappend pinlabels $pintext
158 set tlab [label make pin "$pintext" "$x $y"]
159 label $tlab anchor right
160 label $tlab anchor middle
161 set nlab [element $tlab copy relative "$halfspace 0"]
162 label $nlab type normal
163 label $nlab anchor left
164 incr y $pinspace
165 deselect selected
167 set y [expr -$hheight -$qtrspace]
168 set x [expr -($botpins - 1) * $halfspace]
169 for {set j 0} {$j < $botpins} {incr j} {
170 set taby [expr $y + $qtrspace]
171 polygon make 2 "$x $y" "$x $taby"
172 set pintext [.makesymbol.pinself.bottom.list get $j]
173 lappend pinlabels $pintext
174 set tlab [label make pin "$pintext" "$x $y"]
175 rotate $tlab 270
176 label $tlab anchor right
177 label $tlab anchor middle
178 set nlab [element $tlab copy relative "0 $halfspace"]
179 label $nlab type normal
180 label $nlab anchor left
181 incr x $pinspace
182 deselect selected
184 set y [expr $hheight + $qtrspace]
185 set x [expr -($toppins - 1) * $halfspace]
186 for {set j 0} {$j < $toppins} {incr j} {
187 set taby [expr $y - $qtrspace]
188 polygon make 2 "$x $y" "$x $taby"
189 set pintext [.makesymbol.pinself.top.list get $j]
190 lappend pinlabels $pintext
191 set tlab [label make pin "$pintext" "$x $y"]
192 rotate $tlab 90
193 label $tlab anchor right
194 label $tlab anchor middle
195 set nlab [element $tlab copy relative "0 -$halfspace"]
196 label $nlab type normal
197 label $nlab anchor left
198 incr x $pinspace
199 deselect selected
202 deselect selected
203 set nlab [label make "$symbolname" {0 0}]
204 label $nlab anchor middle
205 label $nlab anchor center
206 element $nlab color set blue
208 deselect selected
209 parameter make substring index "?"
210 parameter make substring class "X"
211 if {$schematicname == $symbolname} {
212 parameter make substring link "%n"
213 } else {
214 parameter make substring link "$schematicname"
217 set nlab [label make "{Parameter class} {Parameter index}" "0 -$pinspace"]
218 label $nlab anchor center
219 element $nlab color set blue
220 deselect selected
222 # Determine if the schematic already has a "subckt" line. If so,
223 # attempt to arrange the pin ordering from it. If not, create one.
224 if {$noschem == 1} {
225 set subckttext ""
226 set pinlabels $orderedpins
227 } else {
228 set subckttext [xcircuit::getsubckttext $schematicname]
231 if {$subckttext == ""} {
232 set subckttext [list {Text "spice1:.subckt %n"}]
233 set pstring ""
234 foreach j $pinlabels {
235 if {[string length $pstring] > 60} {
236 lappend subckttext [subst {Text "$pstring"}]
237 lappend subckttext {Return}
238 set pstring "+"
240 set pstring [join [list $pstring "$j"]] ;# preserves whitespace
242 lappend subckttext [subst {Text "$pstring"}]
244 if {$noschem == 0} {
245 schematic goto
246 set bbox [join [page bbox all]]
247 set x [expr ([lindex $bbox 2] + [lindex $bbox 0]) / 2]
248 set y [expr [lindex $bbox 1] - $pinspace]
249 set nlab [label make info "$subckttext" "$x $y"]
250 label $nlab anchor center
251 deselect selected
252 set y [expr $y - $pinspace]
253 set nlab [label make info "spice-1:.ends" "$x $y"]
254 symbol goto
257 set itext [list {Text "spice:"} {Parameter class} {Parameter index}]
258 set pstring ""
259 foreach j $pinlabels {
260 if {[string length $pstring] > 60} {
261 lappend itext [subst {Text "$pstring"}]
262 lappend itext {Return}
263 set pstring "+"
265 set pstring [join [list $pstring "%p$j"]] ;# preserves whitespace
267 set pstring [join [list $pstring "%n"]] ;# preserves whitespace
268 lappend itext [subst {Text "$pstring"}]
269 } else {
270 set itext [list {Text "spice:"} {Parameter class} {Parameter index}]
271 set pstring ""
272 foreach j [lrange [lindex $subckttext 0] 2 end] {
273 if {[string length $pstring] > 60} {
274 lappend itext [subst {Text "$pstring"}]
275 lappend itext {Return}
276 set pstring "+"
278 set pstring [join [list $pstring "%p$j"]] ;# preserves whitespace
280 set pstring [join [list $pstring "%n"]] ;# preserves whitespace
281 lappend itext [subst {Text "$pstring"}]
284 set y [expr -$hheight - 3 * $pinspace]
286 deselect selected
287 set nlab [label make info "$itext" "0 $y"]
288 label $nlab anchor center
290 if {$noschem == 1} {
291 deselect selected
292 if {[string index $filename 0] != "/"} {
293 set filename [join [concat [pwd] $filename] "/"]
295 set y [expr -$hheight - 4 * $pinspace]
296 set itext [list {Text "spice@1:%F"}]
297 lappend itext [subst {Text "$filename"}]
298 set nlab [label make info "$itext" "0 $y"]
299 label $nlab anchor center
300 deselect selected
302 } else {
303 library $XCOps(library) compose
304 deselect selected
305 symbol goto
306 zoom view
309 config suspend false ;# unlocked state
312 #---------------------------------------------------------------------------
313 # Get the list of pins for the object. If the schematic has a "subckt"
314 # line, then we use the pin names from it, in order. If not, then we
315 # compile a list of all unique pin labels and arrange them in dictionary
316 # alphabetical order.
317 #---------------------------------------------------------------------------
319 proc xcircuit::getpinlist {schematicname} {
320 global XCOps
322 set subckttext [xcircuit::getsubckttext $schematicname]
324 if {$subckttext == {}} {
325 set pinlist {}
326 deselect selected
327 set objlist [object parts]
329 foreach j $objlist {
330 set etype [element $j type]
331 if {$etype == "Label"} {
332 set ltype [label $j type]
333 if {$ltype == "local" || $ltype == "global"} {
335 # Avoid netlist-generated pins by rejecting labels that
336 # don't start with a font specifier.
338 set subtype [lindex [lindex [lindex [label $j list] 0] 0] 0]
339 if {$subtype == "Font"} {
340 lappend pinlist [label $j text]
345 set pinlist [lsort -unique -dictionary $pinlist]
346 } else {
347 set pinlist [lrange [lindex $subckttext 0] 2 end]
349 deselect selected
350 return $pinlist
353 #---------------------------------------------------------------------------
354 # Figure out which list has the selection
355 #---------------------------------------------------------------------------
357 proc xcircuit::getselectedpinwidget {} {
358 set w .makesymbol.pinself.left.list
359 set result [$w curselection]
360 if {$result != {}} {return $w}
362 set w .makesymbol.pinself.top.list
363 set result [$w curselection]
364 if {$result != {}} {return $w}
366 set w .makesymbol.pinself.right.list
367 set result [$w curselection]
368 if {$result != {}} {return $w}
370 set w .makesymbol.pinself.bottom.list
371 set result [$w curselection]
372 if {$result != {}} {return $w}
375 #---------------------------------------------------------------------------
376 # Remove a pin from the pin list
377 #---------------------------------------------------------------------------
379 proc xcircuit::removeselectedpin {} {
380 set w [xcircuit::getselectedpinwidget]
381 if {$w != {}} {
382 set idx [$w curselection]
383 $w delete $idx
387 #---------------------------------------------------------------------------
388 # Move a pin to the left side of the symbol
389 #---------------------------------------------------------------------------
391 proc xcircuit::movepinleft {} {
392 set w [xcircuit::getselectedpinwidget]
393 if {$w != {}} {
394 set idx [$w curselection]
395 set pinname [$w get $idx]
396 $w delete $idx
397 .makesymbol.pinself.left.list insert end $pinname
398 $w selection set $idx
402 #---------------------------------------------------------------------------
403 # Move a pin to the top side of the symbol
404 #---------------------------------------------------------------------------
406 proc xcircuit::movepintop {} {
407 set w [xcircuit::getselectedpinwidget]
408 if {$w != {}} {
409 set idx [$w curselection]
410 set pinname [$w get $idx]
411 $w delete $idx
412 .makesymbol.pinself.top.list insert end $pinname
413 $w selection set $idx
418 #---------------------------------------------------------------------------
419 # Move a pin to the right side of the symbol
420 #---------------------------------------------------------------------------
422 proc xcircuit::movepinright {} {
423 set w [xcircuit::getselectedpinwidget]
424 if {$w != {}} {
425 set idx [$w curselection]
426 set pinname [$w get $idx]
427 $w delete $idx
428 .makesymbol.pinself.right.list insert end $pinname
429 $w selection set $idx
433 #---------------------------------------------------------------------------
434 # Move a pin to the bottom side of the symbol
435 #---------------------------------------------------------------------------
437 proc xcircuit::movepinbottom {} {
438 set w [xcircuit::getselectedpinwidget]
439 if {$w != {}} {
440 set idx [$w curselection]
441 set pinname [$w get $idx]
442 $w delete $idx
443 .makesymbol.pinself.bottom.list insert end $pinname
444 $w selection set $idx
448 #---------------------------------------------------------------------------
449 # Create the pin arranger widget and add it to the dialog box.
450 #---------------------------------------------------------------------------
452 proc xcircuit::addpinarranger {w {pinlist {}}} {
454 frame ${w}.pinself
455 frame ${w}.pinself.left
456 frame ${w}.pinself.top
457 frame ${w}.pinself.right
458 frame ${w}.pinself.bottom
460 label ${w}.pinself.left.title -text "Left Pins"
461 label ${w}.pinself.top.title -text "Top Pins"
462 label ${w}.pinself.right.title -text "Right Pins"
463 label ${w}.pinself.bottom.title -text "Bottom Pins"
465 listbox ${w}.pinself.left.list
466 listbox ${w}.pinself.top.list
467 listbox ${w}.pinself.right.list
468 listbox ${w}.pinself.bottom.list
470 pack ${w}.pinself.left.title -side top
471 pack ${w}.pinself.left.list -side top -fill y -expand true
472 pack ${w}.pinself.top.title -side top
473 pack ${w}.pinself.top.list -side top -fill y -expand true
474 pack ${w}.pinself.right.title -side top
475 pack ${w}.pinself.right.list -side top -fill y -expand true
476 pack ${w}.pinself.bottom.title -side top
477 pack ${w}.pinself.bottom.list -side top -fill y -expand true
479 grid ${w}.pinself.left -row 0 -column 0 -sticky news -padx 1 -pady 1
480 grid ${w}.pinself.top -row 0 -column 1 -sticky news -padx 1 -pady 1
481 grid ${w}.pinself.right -row 0 -column 2 -sticky news -padx 1 -pady 1
482 grid ${w}.pinself.bottom -row 0 -column 3 -sticky news -padx 1 -pady 1
484 grid columnconfigure ${w}.pinself 0 -weight 1 -minsize 50
485 grid columnconfigure ${w}.pinself 1 -weight 1 -minsize 50
486 grid columnconfigure ${w}.pinself 2 -weight 1 -minsize 50
487 grid columnconfigure ${w}.pinself 3 -weight 1 -minsize 50
489 grid rowconfigure ${w}.pinself 0 -weight 1 -minsize 50
491 # Determine if the pinlist is fixed by either being taken from a "subckt"
492 # line in a schematic, or being taken from a "subckt" line in a SPICE deck.
493 # If so, we pass the ordered list to the symbol construction routine, and
494 # we also prevent symbol pins from being deleted.
496 config suspend true ;# suspend graphics and change count
498 if {$pinlist == {}} {
499 set pinlist [xcircuit::getpinlist [page label]]
500 if {[xcircuit::getsubckttext [page label]] != {}} {
501 set orderedpins 1
502 } else {
503 set orderedpins 0
505 } else {
506 set orderedpins 1
509 # Break the pinlist up into 4 parts
511 set rightpins [expr [llength $pinlist] / 2]
512 set bottompins [expr [llength $pinlist] - $rightpins]
513 set leftpins [expr $rightpins / 2]
514 set rightpins [expr $rightpins - $leftpins]
515 set toppins [expr $bottompins / 2]
516 set bottompins [expr $bottompins - $toppins]
517 incr leftpins $rightpins
518 incr bottompins $leftpins
519 incr toppins $bottompins
521 for {set k 0} {$k < $rightpins} {incr k} {
522 ${w}.pinself.right.list insert end [lindex $pinlist $k]
524 for {} {$k < $leftpins} {incr k} {
525 ${w}.pinself.left.list insert end [lindex $pinlist $k]
527 for {} {$k < $bottompins} {incr k} {
528 ${w}.pinself.bottom.list insert end [lindex $pinlist $k]
530 for {} {$k < $toppins} {incr k} {
531 ${w}.pinself.top.list insert end [lindex $pinlist $k]
534 pack ${w}.pinself -side top -anchor w -padx 20 -pady 5 -fill y -expand true
536 catch {
537 if {$orderedpins == 0} {
538 button ${w}.bbar.remove -text "Remove Pin" -bg beige -command \
539 {xcircuit::removeselectedpin}
541 button ${w}.bbar.moveleft -text "Move Left" -bg beige -command \
542 {xcircuit::movepinleft}
543 button ${w}.bbar.movetop -text "Move Top" -bg beige -command \
544 {xcircuit::movepintop}
545 button ${w}.bbar.moveright -text "Move Right" -bg beige -command \
546 {xcircuit::movepinright}
547 button ${w}.bbar.movebottom -text "Move Bottom" -bg beige -command \
548 {xcircuit::movepinbottom}
550 config suspend false
552 if {$orderedpins == 0} {
553 pack ${w}.bbar.remove -side left -ipadx 10
555 pack ${w}.bbar.moveleft -side left -ipadx 10
556 pack ${w}.bbar.movetop -side left -ipadx 10
557 pack ${w}.bbar.moveright -side left -ipadx 10
558 pack ${w}.bbar.movebottom -side left -ipadx 10
561 #---------------------------------------------------------------------------
562 # Remove the pin arranger widget from the dialog box.
563 #---------------------------------------------------------------------------
565 proc xcircuit::removepinarranger {w} {
566 catch {
567 pack forget ${w}.pinself
568 destroy ${w}.pinself
569 pack forget ${w}.bbar.movebottom
570 pack forget ${w}.bbar.moveright
571 pack forget ${w}.bbar.movetop
572 pack forget ${w}.bbar.moveleft
573 pack forget ${w}.bbar.remove
577 #---------------------------------------------------------------------------
578 # Redefine the procedure for the "Make Matching Symbol" menu button.
579 #---------------------------------------------------------------------------
581 proc xcircuit::promptmakesymbol {{name ""}} {
582 global XCOps
583 .makesymbol.bbar.okay configure -command \
584 {if {[string first "Page " [page label]] >= 0} { \
585 page label [.makesymbol.textent.txt get]}; \
586 xcircuit::makesymbol; \
587 wm withdraw .makesymbol}
588 .makesymbol.textent.title.field configure -text "Confirm symbol name:"
589 .makesymbol.textent.txt delete 0 end
590 if {[string length $name] == 0 && [string first "Page " [page label]] < 0} {
591 set name [page label]}
592 .makesymbol.textent.txt insert 0 $name
594 xcircuit::popupdialog .makesymbol
595 xcircuit::addtechlist .makesymbol "Technology: "
596 xcircuit::addliblist .makesymbol "Place in: "
597 xcircuit::addpinarranger .makesymbol
600 #---------------------------------------------------------------------------
601 # Routine which parses a spice file for the first .subckt line and
602 # generates a symbol to match, with a "%F" escape pointing to the
603 # spice file to include.
604 #---------------------------------------------------------------------------
606 proc xcircuit::spice2symbol {filename {subcktname ""}} {
607 global XCOps
609 set f [open $filename]
610 set infolabel ""
611 while {[gets $f line] >= 0} {
612 set dnline [string tolower $line]
613 if {[string first .subckt $dnline] == 0} {
614 while {[gets $f nextline] >= 0} {
615 if {[string first + $nextline] != 0} {break}
616 append line [string range $nextline 1 end]
618 set infolabel $line
619 if {$subcktname == ""} {break}
620 if {[string compare $subcktname [lindex $infolabel 1]] == 0} {break}
623 close $f
625 if {[string length $infolabel] == 0} {return}
626 set pinlabels [lrange $infolabel 2 end]
628 .makesymbol.bbar.okay configure -command \
629 "if {[string first {Page } [page label]] >= 0} { \
630 page label [.makesymbol.textent.txt get]}; \
631 xcircuit::makesymbol $filename [list $pinlabels]; \
632 wm withdraw .makesymbol"
633 .makesymbol.textent.title.field configure -text "Confirm symbol name:"
634 .makesymbol.textent.txt delete 0 end
635 .makesymbol.textent.txt insert 0 [lindex $infolabel 1]
636 xcircuit::popupdialog .makesymbol
637 xcircuit::addliblist .makesymbol "Place in: "
638 xcircuit::addpinarranger .makesymbol $pinlabels
641 #---------------------------------------------------------------------------
642 # Procedure that creates the dialog to find a spice file to parse and
643 # calls spice2symbol.
644 #---------------------------------------------------------------------------
646 proc xcircuit::promptspicesymbol {} {
647 global XCOps
648 .filelist.bbar.okay configure -command \
649 {xcircuit::spice2symbol [.filelist.textent.txt get] ; \
650 wm withdraw .filelist}
651 .filelist.listwin.win configure -data "cir"
652 .filelist.textent.title.field configure -text "Select spice file to parse:"
653 .filelist.textent.txt delete 0 end
654 xcircuit::popupfilelist
655 xcircuit::removelists .filelist
658 #---------------------------------------------------------------------------
659 # Add a menu item to invoke promptspicesymbol.
660 #---------------------------------------------------------------------------
662 set m .xcircuit.menubar.netlistbutton.netlistmenu
663 $m insert 7 command -label "SPICE to symbol" -command {xcircuit::promptspicesymbol}
664 unset m
666 #---------------------------------------------------------------------------