1# This is the "Magic wrapper". 2# Its main purpose is to redefine the "openwindow" command in magic so that 3# opening a new window creates a window wrapped by a GUI interface. 4# 5# Written by Tim Edwards, August 23, 2002. 6 7# revision A: proof-of-concept. Add whatever you want to this basic wrapper. 8# revision B: Adds Tk scrollbars and caption 9# revision C: Adds a layer manager toolbar on the left side 10# revision D: Adds a menubar on top with cell and tech manager tools 11 12global lwindow 13global tk_version 14global Glyph 15global Opts 16global Winopts 17 18set tk_version $::tk_version 19# Simple console commands (like TkCon, but much simpler) 20 21if {[lsearch [namespace children] ::tkshell] < 0} { 22 catch {source ${CAD_ROOT}/magic/tcl/tkshell.tcl} 23} 24 25proc magic::makeglyphimages {} { 26 global Opts 27 global Glyph 28 global CAD_ROOT 29 30 # Check if glyphs exist---don't need to make them more than once 31 if {![catch {set Glyph(up)}]} {return} 32 33 # Glyph images 34 35 set gsize [expr {int($Opts(scale) * 13)}] 36 set gscale [expr {int($Opts(scale))}] 37 38 image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/up.gif 39 image create photo Glyph(up) -width $gsize -height $gsize 40 Glyph(up) copy stdglyph -zoom $gscale 41 42 image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/down.gif 43 image create photo Glyph(down) -width $gsize -height $gsize 44 Glyph(down) copy stdglyph -zoom $gscale 45 46 image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/left.gif 47 image create photo Glyph(left) -width $gsize -height $gsize 48 Glyph(left) copy stdglyph -zoom $gscale 49 50 image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/right.gif 51 image create photo Glyph(right) -width $gsize -height $gsize 52 Glyph(right) copy stdglyph -zoom $gscale 53 54 image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/zoom.gif 55 image create photo Glyph(zoom) -width $gsize -height $gsize 56 Glyph(zoom) copy stdglyph -zoom $gscale 57 58 image create bitmap Glyph(lock) \ 59 -file ${CAD_ROOT}/magic/tcl/bitmaps/lock.xbm \ 60 -background gray80 -foreground steelblue4] 61} 62 63# Menu button callback functions 64 65proc magic::promptload {type} { 66 global CAD_ROOT 67 68 switch $type { 69 cif { set Layoutfilename [ tk_getOpenFile -filetypes \ 70 {{CIF {.cif {.cif}}} {"All files" {*}}}] 71 if {$Layoutfilename != ""} { 72 set cifname [file tail [file root $Layoutfilename]] 73 magic::cellname create cif_temp 74 magic::load cif_temp 75 magic::cif read [file root $Layoutfilename] 76 set childcells [magic::cellname list children cif_temp] 77 magic::load [lindex $childcells 0] 78 magic::cellname delete cif_temp -noprompt 79 if {[llength $childcells] > 1} { 80 puts stdout "Cells read from GDS file: $childcells" 81 } 82 } 83 } 84 gds { set Layoutfilename [ tk_getOpenFile -filetypes \ 85 {{GDS {.gds .strm .cal {.gds .strm .cal}}} {"All files" {*}}}] 86 if {$Layoutfilename != ""} { 87 set origlist [magic::cellname list top] 88 magic::gds read [file root $Layoutfilename] 89 set newlist [magic::cellname list top] 90 91 # Find entries in newlist that are not in origlist. 92 # If there's only one, load it into the window. 93 94 set newtopcells {} 95 foreach n $newlist { 96 if {[lsearch $origlist $n] < 0} { 97 lappend newtopcells $n 98 } 99 } 100 if {[llength $newtopcells] == 1} { 101 magic::load [lindex $newtopcells 0] 102 } elseif {[llength $newtopcells] != 0} { 103 puts stdout "Top-level cells read from GDS file: $newtopcells" 104 } 105 } 106 } 107 magic { set Layoutfilename [ tk_getOpenFile -filetypes \ 108 {{Magic {.mag {.mag}}} {"All files" {*}}}] 109 if {$Layoutfilename != ""} { 110 magic::load [file root $Layoutfilename] 111 } 112 } 113 114 getcell { set Layoutfilename [ tk_getOpenFile -filetypes \ 115 {{Magic {.mag {.mag}}} {"All files" {*}}}] 116 if {$Layoutfilename != ""} { 117 set fdir [file dirname $Layoutfilename] 118 set lidx [lsearch [path search] $fdir] 119 if {$lidx < 0} {path search +$fdir} 120 magic::getcell [file tail $Layoutfilename] 121 122 # Append path to cell search path if it's not there already 123 124 if {[string index $Layoutfilename 0] != "/"} { 125 set $Layoutfilename "./$Layoutfilename" 126 } 127 set sidx [string last "/" $Layoutfilename] 128 if {$sidx > 0} { 129 set cellpath [string range $Layoutfilename 0 $sidx] 130 magic::path cell +$cellpath 131 } 132 } 133 } 134 } 135} 136 137proc magic::promptsave {type} { 138 global CAD_ROOT 139 140 switch $type { 141 cif { set Layoutfilename [ tk_getSaveFile -filetypes \ 142 {{CIF {.cif {.cif}}} {"All files" {*}}}] 143 if {$Layoutfilename != ""} { 144 magic::cif write $Layoutfilename 145 } 146 } 147 gds { set Layoutfilename [ tk_getSaveFile -filetypes \ 148 {{GDS {.gds .strm .cal {.gds .strm .cal}}} {"All files" {*}}}] 149 if {$Layoutfilename != ""} { 150 magic::gds write $Layoutfilename 151 } 152 } 153 force - 154 magic { 155 set CellList [ magic::cellname list window ] 156 if {[lsearch $CellList "(UNNAMED)"] >= 0} { 157 set Layoutfilename [ tk_getSaveFile -filetypes \ 158 {{Magic {.mag {.mag}}} {"All files" {*}}} \ 159 -title "Save cell (UNNAMED) as:" ] 160 if {$Layoutfilename != ""} { 161 set cellpath [file dirname $Layoutfilename] 162 if {$cellpath == [pwd]} { 163 set Layoutfilename [file tail $Layoutfilename] 164 } else { 165 magic::path cell +$cellpath 166 } 167 magic::save $Layoutfilename 168 } 169 } 170 if {$type == "force"} { 171 magic::writeall force 172 } else { 173 magic::writeall 174 } 175 } 176 } 177} 178 179# Window to prompt for a new cell 180 181proc magic::prompt_dialog { type } { 182 global Opts 183 184 if {[catch {toplevel .dialog}]} { 185 foreach child [winfo children .dialog] { 186 destroy $child 187 } 188 } 189 190 frame .dialog.titlebar 191 frame .dialog.text 192 frame .dialog.bbar 193 194 switch $type { 195 new { 196 label .dialog.titlebar.title -text "Create new cell" -foreground blue 197 button .dialog.bbar.okay -text "Okay" -command {load $Opts(cell_name); \ 198 lower .dialog} 199 set Opts(cell_name) "(UNNAMED)" 200 } 201 save { 202 label .dialog.titlebar.title -text "Save cell as..." -foreground blue 203 button .dialog.bbar.okay -text "Okay" -command {save $Opts(cell_name); \ 204 lower .dialog} 205 set Opts(cell_name) [cellname list window] 206 } 207 } 208 pack .dialog.titlebar.title 209 210 label .dialog.text.tlabel -text "Cell name:" -foreground brown 211 entry .dialog.text.tentry -background white -textvariable Opts(cell_name) 212 213 pack .dialog.text.tlabel -side left 214 pack .dialog.text.tentry -side left 215 216 button .dialog.bbar.cancel -text "Cancel" -command "lower .dialog" 217 218 pack .dialog.bbar.okay -side left 219 pack .dialog.bbar.cancel -side right 220 221 pack .dialog.titlebar -side top -ipadx 2 -ipady 2 222 pack .dialog.text -side top -fill both -expand true 223 pack .dialog.bbar -side top -fill x -ipadx 5 224 225 bind .dialog.text.tentry <Return> {.dialog.bbar.okay invoke} 226 227 raise .dialog 228} 229 230# Callback functions used by the DRC. 231 232proc magic::drcupdate { option } { 233 global Opts 234 if {[info level] <= 1} { 235 switch $option { 236 on {set Opts(drc) 1} 237 off {set Opts(drc) 0} 238 } 239 } 240} 241 242proc magic::drcstate { status } { 243 set winlist [*bypass windownames layout] 244 foreach lwin $winlist { 245 set framename [winfo parent $lwin] 246 if {$framename == "."} {return} 247 switch $status { 248 idle { 249 set dct [*bypass drc list count total] 250 if {$dct > 0} { 251 ${framename}.titlebar.drcbutton configure -selectcolor red 252 } else { 253 ${framename}.titlebar.drcbutton configure -selectcolor green 254 } 255 ${framename}.titlebar.drcbutton configure -text "DRC=$dct" 256 } 257 busy { ${framename}.titlebar.drcbutton configure -selectcolor yellow } 258 } 259 } 260} 261 262# Create the menu of windows. This is kept separate from the cell manager, 263# and linked into it by the "clone" command. 264 265menu .winmenu -tearoff 0 266 267proc magic::setgrid {gridsize} { 268 set techlambda [magic::tech lambda] 269 set tech1 [lindex $techlambda 1] 270 set tech0 [lindex $techlambda 0] 271 set tscale [expr {$tech1 / $tech0}] 272 set lambdaout [expr {[magic::cif scale output] * $tscale}] 273 set gridlambda [expr {$gridsize/$lambdaout}] 274 magic::grid ${gridlambda}l 275 magic::snap on 276} 277 278# Technology manager callback functions 279 280proc magic::techparseunits {} { 281 set techlambda [magic::tech lambda] 282 set tech1 [lindex $techlambda 1] 283 set tech0 [lindex $techlambda 0] 284 285 set target0 [.techmgr.lambda1.lval0 get] 286 set target1 [.techmgr.lambda1.lval1 get] 287 288 set newval0 [expr {$target0 * $tech0}] 289 set newval1 [expr {$target1 * $tech1}] 290 291 magic::scalegrid $newval1 $newval0 292 magic::techmanager update 293} 294 295# The technology manager 296 297proc magic::maketechmanager { mgrpath } { 298 toplevel $mgrpath 299 wm withdraw $mgrpath 300 301 frame ${mgrpath}.title 302 label ${mgrpath}.title.tlab -text "Technology: " 303 menubutton ${mgrpath}.title.tname -text "(none)" -foreground red3 \ 304 -menu ${mgrpath}.title.tname.menu 305 label ${mgrpath}.title.tvers -text "" -foreground blue 306 label ${mgrpath}.subtitle -text "" -foreground sienna4 307 308 frame ${mgrpath}.lambda0 309 label ${mgrpath}.lambda0.llab -text "Microns per lambda (CIF): " 310 label ${mgrpath}.lambda0.lval -text "1" -foreground blue 311 312 frame ${mgrpath}.lambda1 313 label ${mgrpath}.lambda1.llab -text "Internal units per lambda: " 314 entry ${mgrpath}.lambda1.lval0 -foreground red3 -background white -width 3 315 label ${mgrpath}.lambda1.ldiv -text " / " 316 entry ${mgrpath}.lambda1.lval1 -foreground red3 -background white -width 3 317 318 frame ${mgrpath}.cif0 319 label ${mgrpath}.cif0.llab -text "CIF input style: " 320 menubutton ${mgrpath}.cif0.lstyle -text "" -foreground blue \ 321 -menu ${mgrpath}.cif0.lstyle.menu 322 label ${mgrpath}.cif0.llab2 -text " Microns/lambda=" 323 label ${mgrpath}.cif0.llambda -text "" -foreground red3 324 325 frame ${mgrpath}.cif1 326 label ${mgrpath}.cif1.llab -text "CIF output style: " 327 menubutton ${mgrpath}.cif1.lstyle -text "" -foreground blue \ 328 -menu ${mgrpath}.cif1.lstyle.menu 329 label ${mgrpath}.cif1.llab2 -text " Microns/lambda=" 330 label ${mgrpath}.cif1.llambda -text "" -foreground red3 331 332 frame ${mgrpath}.extract 333 label ${mgrpath}.extract.llab -text "Extract style: " 334 menubutton ${mgrpath}.extract.lstyle -text "" -foreground blue \ 335 -menu ${mgrpath}.extract.lstyle.menu 336 337 frame ${mgrpath}.drc 338 label ${mgrpath}.drc.llab -text "DRC style: " 339 menubutton ${mgrpath}.drc.lstyle -text "" -foreground blue \ 340 -menu ${mgrpath}.drc.lstyle.menu 341 342 pack ${mgrpath}.title.tlab -side left 343 pack ${mgrpath}.title.tname -side left 344 pack ${mgrpath}.title.tvers -side left 345 pack ${mgrpath}.lambda0.llab -side left 346 pack ${mgrpath}.lambda0.lval -side left 347 pack ${mgrpath}.lambda1.llab -side left 348 pack ${mgrpath}.lambda1.lval0 -side left 349 pack ${mgrpath}.lambda1.ldiv -side left 350 pack ${mgrpath}.lambda1.lval1 -side left 351 pack ${mgrpath}.cif0.llab -side left 352 pack ${mgrpath}.cif0.lstyle -side left 353 pack ${mgrpath}.cif0.llab2 -side left 354 pack ${mgrpath}.cif0.llambda -side left 355 pack ${mgrpath}.cif1.llab -side left 356 pack ${mgrpath}.cif1.lstyle -side left 357 pack ${mgrpath}.cif1.llab2 -side left 358 pack ${mgrpath}.cif1.llambda -side left 359 pack ${mgrpath}.extract.llab -side left 360 pack ${mgrpath}.extract.lstyle -side left 361 pack ${mgrpath}.drc.llab -side left 362 pack ${mgrpath}.drc.lstyle -side left 363 364 pack ${mgrpath}.title -side top -fill x 365 pack ${mgrpath}.subtitle -side top -fill x 366 pack ${mgrpath}.lambda0 -side top -fill x 367 pack ${mgrpath}.lambda1 -side top -fill x 368 pack ${mgrpath}.cif0 -side top -fill x 369 pack ${mgrpath}.cif1 -side top -fill x 370 pack ${mgrpath}.extract -side top -fill x 371 372 bind ${mgrpath}.lambda1.lval0 <Return> magic::techparseunits 373 bind ${mgrpath}.lambda1.lval1 <Return> magic::techparseunits 374 375 #Withdraw the window when the close button is pressed 376 wm protocol ${mgrpath} WM_DELETE_WINDOW "set Opts(techmgr) 0 ; wm withdraw ${mgrpath}" 377} 378 379# Generate the cell manager 380 381catch {source ${CAD_ROOT}/magic/tcl/cellmgr.tcl} 382 383# Generate the library manager 384 385catch {source ${CAD_ROOT}/magic/tcl/libmgr.tcl} 386 387# Generate the DRC manager 388 389catch {source ${CAD_ROOT}/magic/tcl/drcmgr.tcl} 390 391# Generate the text helper 392 393catch {source ${CAD_ROOT}/magic/tcl/texthelper.tcl} 394 395# Create or redisplay the technology manager 396 397proc magic::techmanager {{option "update"}} { 398 global CAD_ROOT 399 400 if {[catch {wm state .techmgr}]} { 401 if {$option == "create"} { 402 magic::maketechmanager .techmgr 403 } else { 404 return 405 } 406 } elseif { $option == "create"} { 407 return 408 } 409 410 if {$option == "create"} { 411 menu .techmgr.title.tname.menu -tearoff 0 412 menu .techmgr.cif0.lstyle.menu -tearoff 0 413 menu .techmgr.cif1.lstyle.menu -tearoff 0 414 menu .techmgr.extract.lstyle.menu -tearoff 0 415 menu .techmgr.drc.lstyle.menu -tearoff 0 416 417 } 418 419 if {$option == "init"} { 420 .techmgr.title.tname.menu delete 0 end 421 .techmgr.cif0.lstyle.menu delete 0 end 422 .techmgr.cif1.lstyle.menu delete 0 end 423 .techmgr.extract.lstyle.menu delete 0 end 424 .techmgr.drc.lstyle.menu delete 0 end 425 } 426 427 if {$option == "init" || $option == "create"} { 428 set tlist [magic::cif listall istyle] 429 foreach i $tlist { 430 .techmgr.cif0.lstyle.menu add command -label $i -command \ 431 "magic::cif istyle $i ; \ 432 magic::techmanager update" 433 } 434 435 set tlist [magic::cif listall ostyle] 436 foreach i $tlist { 437 .techmgr.cif1.lstyle.menu add command -label $i -command \ 438 "magic::cif ostyle $i ; \ 439 magic::techmanager update" 440 } 441 442 set tlist [magic::extract listall style] 443 foreach i $tlist { 444 .techmgr.extract.lstyle.menu add command -label $i -command \ 445 "magic::extract style $i ; \ 446 magic::techmanager update" 447 } 448 449 set tlist [magic::drc listall style] 450 foreach i $tlist { 451 .techmgr.drc.lstyle.menu add command -label $i -command \ 452 "magic::drc style $i ; \ 453 magic::techmanager update" 454 } 455 456 set dirlist [subst [magic::path sys]] 457 set tlist {} 458 foreach i $dirlist { 459 lappend tlist [glob -nocomplain ${i}/*.tech] 460 lappend tlist [glob -nocomplain ${i}/*.tech27] 461 } 462 foreach i [join $tlist] { 463 set j [file tail [file rootname ${i}]] 464 .techmgr.title.tname.menu add command -label $j -command \ 465 "magic::tech load $j ; \ 466 magic::techmanager update" 467 } 468 } 469 470 set techlambda [magic::tech lambda] 471 set tech1 [lindex $techlambda 1] 472 set tech0 [lindex $techlambda 0] 473 set tscale [expr {$tech1 / $tech0}] 474 475 .techmgr.title.tname configure -text [magic::tech name] 476 set techstuff [magic::tech version] 477 .techmgr.title.tvers configure -text "(version [lindex $techstuff 0])" 478 .techmgr.subtitle configure -text [lindex $techstuff 1] 479 set lotext [format "%g" [expr {[magic::cif scale output] * $tscale}]] 480 .techmgr.lambda0.lval configure -text $lotext 481 .techmgr.cif0.lstyle configure -text [magic::cif list istyle] 482 set litext [format "%g" [expr {[magic::cif scale input] * $tscale}]] 483 .techmgr.cif0.llambda configure -text $litext 484 .techmgr.cif1.lstyle configure -text [magic::cif list ostyle] 485 .techmgr.cif1.llambda configure -text $lotext 486 .techmgr.extract.lstyle configure -text [magic::extract list style] 487 .techmgr.drc.lstyle configure -text [magic::drc list style] 488 489 .techmgr.lambda1.lval0 delete 0 end 490 .techmgr.lambda1.lval1 delete 0 end 491 .techmgr.lambda1.lval0 insert end $tech1 492 .techmgr.lambda1.lval1 insert end $tech0 493} 494 495proc magic::captions {{subcommand {}}} { 496 global Opts 497 498 if {$subcommand != {} && $subcommand != "writeable" && $subcommand != "load"} { 499 return 500 } 501 set winlist [magic::windownames layout] 502 foreach winpath $winlist { 503 set framename [winfo parent $winpath] 504 set caption [$winpath windowcaption] 505 set subcaption1 [lindex $caption 0] 506 set techname [tech name] 507 if {[catch {set Opts(tool)}]} { 508 set Opts(tool) unknown 509 } 510 if {[lindex $caption 1] == "EDITING"} { 511 set subcaption2 [lindex $caption 2] 512 } else { 513 # set subcaption2 [join [lrange $caption 1 end]] 514 set subcaption2 $caption 515 } 516 ${framename}.titlebar.caption configure -text \ 517 "Loaded: ${subcaption1} Editing: ${subcaption2} Tool: $Opts(tool) \ 518 Technology: ${techname}" 519 } 520} 521 522# Allow captioning in the title window by tagging the "load" and "edit" commands 523# Note that the "box" tag doesn't apply to mouse-button events, so this function 524# is duplicated by Tk binding of mouse events in the layout window. 525 526magic::tag load "[magic::tag load]; magic::captions" 527magic::tag edit "magic::captions" 528magic::tag save "magic::captions" 529magic::tag down "magic::captions" 530magic::tag box "magic::boxview %W %1" 531magic::tag move "magic::boxview %W" 532magic::tag scroll "magic::scrollupdate %W" 533magic::tag view "magic::scrollupdate %W" 534magic::tag zoom "magic::scrollupdate %W" 535magic::tag findbox "magic::scrollupdate %W" 536magic::tag see "magic::toolupdate %W %1 %2" 537magic::tag tech "magic::techrebuild %W %1; magic::captions %1" 538magic::tag drc "magic::drcupdate %1" 539magic::tag path "[magic::tag path]; magic::techmanager update" 540magic::tag cellname "magic::mgrupdate %W %1" 541magic::tag cif "magic::mgrupdate %W %1" 542magic::tag gds "magic::mgrupdate %W %1" 543 544# This should be a list. . . do be done later 545set lwindow 0 546set owindow 0 547 548set Opts(techmgr) 0 549set Opts(target) default 550set Opts(netlist) 0 551set Opts(colormap) 0 552set Opts(wind3d) 0 553set Opts(crosshair) 0 554set Opts(hidelocked) 0 555set Opts(hidespecial) 0 556set Opts(toolbar) 0 557set Opts(toolscale) 1.0 558set Opts(drc) 1 559set Opts(autobuttontext) 1 560 561# Update cell and tech managers in response to a cif or gds read command 562 563proc magic::mgrupdate {win {cmdstr ""}} { 564 if {${cmdstr} == "read"} { 565 catch {magic::cellmanager} 566 magic::captions 567 magic::techmanager update 568 } elseif {${cmdstr} == "delete" || ${cmdstr} == "rename"} { 569 catch {magic::cellmanager} 570 magic::captions 571 } elseif {${cmdstr} == "writeable"} { 572 magic::captions 573 } 574} 575 576# Set default width and height to be 3/4 of the screen size. 577set Opts(geometry) \ 578"[expr {3 * [winfo screenwidth .] / 4}]x[expr {3 * [winfo screenheight .] \ 579/ 4}]+100+100" 580 581# Procedures for the layout scrollbars, which are made from canvas 582# objects to avoid the problems associated with Tk's stupid scrollbar 583# implementation. 584 585# Repainting function for scrollbars, title, etc., to match the magic 586# Change the colormap (most useful in 8-bit PseudoColor) 587 588proc magic::repaintwrapper { win } { 589 set bgcolor [magic::magiccolor -] 590 ${win}.xscroll configure -background $bgcolor 591 ${win}.xscroll configure -highlightbackground $bgcolor 592 ${win}.xscroll configure -highlightcolor [magic::magiccolor K] 593 594 ${win}.yscroll configure -background $bgcolor 595 ${win}.yscroll configure -highlightbackground $bgcolor 596 ${win}.yscroll configure -highlightcolor [magic::magiccolor K] 597 598 ${win}.titlebar.caption configure -background [magic::magiccolor w] 599 ${win}.titlebar.caption configure -foreground [magic::magiccolor c] 600 601 ${win}.titlebar.message configure -background [magic::magiccolor w] 602 ${win}.titlebar.message configure -foreground [magic::magiccolor c] 603 604 ${win}.titlebar.pos configure -background [magic::magiccolor w] 605 ${win}.titlebar.pos configure -foreground [magic::magiccolor c] 606 607} 608 609# Coordinate display callback function 610# Because "box" calls "box", use the "info level" command to avoid 611# infinite recursion. 612 613proc magic::boxview {win {cmdstr ""}} { 614 if {${cmdstr} == "exists" || ${cmdstr} == "help" || ${cmdstr} == ""} { 615 # do nothing. . . informational only, no change to the box 616 } elseif {${cmdstr} == "remove"} { 617 set framename [winfo parent $win] 618 if {$framename == "."} {return} 619 ${framename}.titlebar.pos configure -text "no box" 620 } elseif {[info level] <= 1} { 621 # For NULL window, find all layout windows and apply update to each. 622 if {$win == {}} { 623 set winlist [magic::windownames layout] 624 foreach lwin $winlist { 625 magic::boxview $lwin 626 } 627 return 628 } 629 630 set framename [winfo parent $win] 631 if {$framename == "."} {return} 632 if {[catch {set cr [cif scale out]}]} {return} 633 set bval [${win} box values] 634 set bllx [expr {[lindex $bval 0] * $cr }] 635 set blly [expr {[lindex $bval 1] * $cr }] 636 set burx [expr {[lindex $bval 2] * $cr }] 637 set bury [expr {[lindex $bval 3] * $cr }] 638 if {[expr {$bllx == int($bllx)}]} {set bllx [expr {int($bllx)}]} 639 if {[expr {$blly == int($blly)}]} {set blly [expr {int($blly)}]} 640 if {[expr {$burx == int($burx)}]} {set burx [expr {int($burx)}]} 641 if {[expr {$bury == int($bury)}]} {set bury [expr {int($bury)}]} 642 set titletext [format "box (%+g %+g) to (%+g %+g) microns" \ 643 $bllx $blly $burx $bury] 644 ${framename}.titlebar.pos configure -text $titletext 645 } 646} 647 648proc magic::cursorview {win} { 649 global Opts 650 if {$win == {}} { 651 return 652 } 653 set framename [winfo parent $win] 654 if {[catch {set cr [*bypass cif scale out]}]} {return} 655 if {$cr == 0} {return} 656 set olst [${win} cursor internal] 657 658 set olstx [lindex $olst 0] 659 set olsty [lindex $olst 1] 660 661 if {$Opts(crosshair)} { 662 *bypass crosshair ${olstx}i ${olsty}i 663 } 664 665 # Use catch, because occasionally this fails on startup 666 if {[catch { 667 set olstx [expr {$olstx * $cr}] 668 set olsty [expr {$olsty * $cr}] 669 }]} {return} 670 671 if {[${win} box exists]} { 672 set dlst [${win} box position] 673 set dx [expr {$olstx - ([lindex $dlst 0]) * $cr }] 674 set dy [expr {$olsty - ([lindex $dlst 1]) * $cr }] 675 if {[expr {$dx == int($dx)}]} {set dx [expr {int($dx)}]} 676 if {[expr {$dy == int($dy)}]} {set dy [expr {int($dy)}]} 677 set titletext [format "(%+g %+g) %+g %+g microns" $olstx $olsty $dx $dy] 678 ${framename}.titlebar.pos configure -text $titletext 679 } else { 680 set titletext [format "(%+g %+g) microns" $olstx $olsty] 681 ${framename}.titlebar.pos configure -text $titletext 682 } 683} 684 685proc magic::toolupdate {win {yesno "yes"} {layerlist "none"}} { 686 global Winopts 687 688 if {$win == {}} { 689 set win [magic::windownames] 690 } 691 692 # Wind3d has a "see" function, so make sure this is not a 3d window 693 if {$win == [magic::windownames wind3d]} { 694 return 695 } 696 697 set topname [winfo toplevel $win] 698 set framename [winfo parent $win] 699 700 # Don't do anything if toolbar is not present 701 if { $Winopts(${topname},toolbar) == 0 } { return } 702 703 if {$layerlist == "none"} { 704 set layerlist $yesno 705 set yesno "yes" 706 } 707 if {$layerlist == "*"} { 708 set layerlist [magic::tech layer "*"] 709 } 710 711 # Change from comma-separated list to Tcl list 712 set layerlist [string map {, " "} $layerlist] 713 714 foreach layer $layerlist { 715 switch $layer { 716 none {set canon ""} 717 allSame {set canon ""} 718 "*" {set canon ""} 719 "$" {set canon ""} 720 connect {set canon ""} 721 errors {set canon $layer} 722 subcell {set canon $layer} 723 labels {set canon $layer} 724 default {set canon [magic::tech layer $layer]} 725 } 726 727 # Layers may not be in the toolbar if "hidelocked" or 728 # "hidespecial" is used, so catch each configure command. 729 730 if {$canon != ""} { 731 if {$yesno == "yes"} { 732 catch {${framename}.toolbar.b$canon configure -image img_$canon} 733 catch {${framename}.toolbar.p$canon configure -image pale_$canon} 734 } else { 735 catch {${framename}.toolbar.b$canon configure -image img_space} 736 catch {${framename}.toolbar.p$canon configure -image img_space} 737 } 738 } 739 } 740} 741 742# Generate the toolbar images for a technology 743 744proc magic::maketoolimages {} { 745 global Opts 746 747 # Tool size expands with the GUI scale but can also be expanded independently. 748 set tsize [expr {int($Opts(scale) * $Opts(toolscale) * 16)}] 749 750 # Generate a layer image for "space" that will be used when layers are 751 # invisible. 752 753 image create layer img_space -name none -width $tsize -height $tsize 754 755 set all_layers [concat {errors labels subcell} [magic::tech layer "*"]] 756 757 foreach layername $all_layers { 758 image create layer img_$layername -name $layername -width $tsize -height $tsize 759 image create layer pale_$layername -name $layername \ 760 -disabled true -icon 23 -width $tsize -height $tsize 761 } 762} 763 764# Generate the toolbar for the wrapper 765 766proc magic::maketoolbar { framename } { 767 global Opts 768 global Winopts 769 770 # Don't do anything if in suspend mode 771 set topname [winfo toplevel $framename] 772 if {[info exists Winopts(${topname},suspend)]} { 773 if { $Winopts(${topname},suspend) > 0} { return } 774 } 775 776 if {$Opts(toolbar) == 0} { 777 magic::maketoolimages 778 set Opts(toolbar) 1 779 } 780 781 # Destroy any existing toolbar before starting 782 set alltools [winfo children ${framename}.toolbar] 783 foreach i $alltools { 784 destroy $i 785 } 786 787 # All toolbar commands will be passed to the appropriate window 788 set win ${framename}.magic 789 790 # Generate layer images and buttons for toolbar 791 if {$Opts(hidespecial) == 0} { 792 set special_layers {errors labels subcell} 793 } else { 794 set special_layers {} 795 } 796 797 if {$Opts(hidelocked) == 0} { 798 set all_layers [concat $special_layers [magic::tech layer "*"]] 799 } else { 800 set all_layers [concat $special_layers [magic::tech unlocked]] 801 } 802 foreach layername $all_layers { 803 button ${framename}.toolbar.b$layername -image img_$layername -command \ 804 "$win see $layername" 805 806 # Bindings: Entering the button puts the canonical layer name in the 807 # message window. 808 bind ${framename}.toolbar.b$layername <Enter> \ 809 [subst {focus %W ; ${framename}.titlebar.message configure \ 810 -text "$layername"}] 811 bind ${framename}.toolbar.b$layername <Leave> \ 812 [subst {${framename}.titlebar.message configure -text ""}] 813 814 # 3rd mouse button makes layer invisible; 1st mouse button restores it. 815 # 2nd mouse button paints the layer color. Key "p" also does paint, esp. 816 # for users with 2-button mice. Key "e" erases, as does Shift-Button-2. 817 818 bind ${framename}.toolbar.b$layername <ButtonPress-2> \ 819 "$win paint $layername" 820 bind ${framename}.toolbar.b$layername <KeyPress-p> \ 821 "$win paint $layername" 822 bind ${framename}.toolbar.b$layername <Shift-ButtonPress-2> \ 823 "$win erase $layername" 824 bind ${framename}.toolbar.b$layername <KeyPress-e> \ 825 "$win erase $layername" 826 bind ${framename}.toolbar.b$layername <ButtonPress-3> \ 827 "$win see no $layername" 828 bind ${framename}.toolbar.b$layername <KeyPress-s> \ 829 "$win select more area $layername" 830 bind ${framename}.toolbar.b$layername <KeyPress-S> \ 831 "$win select less area $layername" 832 } 833 834 # Create an additional set of layers and buttons in the "disabled" style 835 # These buttons can be swapped in place of the regular buttons when the 836 # layer is locked. They define no bindings except "u" for "unlock", 837 # and the button bindings (see, see no) 838 839 foreach layername $all_layers { 840 button ${framename}.toolbar.p$layername -image pale_$layername -command \ 841 "$win see $layername" 842 bind ${framename}.toolbar.p$layername <ButtonPress-3> \ 843 "$win see no $layername" 844 bind ${framename}.toolbar.p$layername <Enter> \ 845 [subst {focus %W ; ${framename}.titlebar.message configure \ 846 -text "$layername (locked)"}] 847 bind ${framename}.toolbar.p$layername <Leave> \ 848 [subst {${framename}.titlebar.message configure -text ""}] 849 } 850 851 # Figure out how many columns we need to fit all the layer buttons inside 852 # the toolbar without going outside the window area. 853 854 set locklist [tech locked] 855 set ncols 0 856 while {1} { 857 incr ncols 858 set i 0 859 set j 0 860 foreach layername $all_layers { 861 if {[lsearch $locklist $layername] >= 0} { 862 grid ${framename}.toolbar.p$layername -row $i -column $j -sticky news 863 } else { 864 grid ${framename}.toolbar.b$layername -row $i -column $j -sticky news 865 } 866 bind ${framename}.toolbar.p$layername <KeyPress-u> \ 867 "$win tech unlock $layername ; \ 868 grid forget ${framename}.toolbar.p$layername ; \ 869 grid ${framename}.toolbar.b$layername \ 870 -row $i -column $j -sticky news" 871 bind ${framename}.toolbar.b$layername <KeyPress-l> \ 872 "$win tech lock $layername ; \ 873 grid forget ${framename}.toolbar.b$layername ; \ 874 grid ${framename}.toolbar.p$layername \ 875 -row $i -column $j -sticky news" 876 incr j 877 if {$j == $ncols} { 878 set j 0 879 incr i 880 } 881 } 882 883 # Make sure that window has been created so we will get the correct 884 # height value. 885 886 update idletasks 887 set winheight [expr {[winfo height ${framename}] - \ 888 [winfo height ${framename}.titlebar]}] 889 set toolheight [lindex [grid bbox ${framename}.toolbar] 3] 890 if {$toolheight <= $winheight} {break} 891 } 892} 893 894# Delete and rebuild the toolbar buttons in response to a "tech load" 895# command. 896 897proc magic::techrebuild {winpath {cmdstr ""}} { 898 global Opts 899 900 # For NULL window, find all layout windows and apply update to each. 901 if {$winpath == {}} { 902 set winlist [magic::windownames layout] 903 foreach lwin $winlist { 904 magic::techrebuild $lwin $cmdstr 905 } 906 return 907 } 908 909 set framename [winfo parent $winpath] 910 if {${cmdstr} == "load"} { 911 set Opts(toolbar) 0 912 maketoolbar ${framename} 913 magic::techmanager init 914 } elseif {${cmdstr} == "lock" || ${cmdstr} == "unlock" || ${cmdstr} == "revert"} { 915 maketoolbar ${framename} 916 } 917} 918 919# Scrollbar callback procs 920 921# Procedure to return the effective X and Y scrollbar bounds for the 922# current view in magic (in pixels) 923 924proc magic::setscrollvalues {win} { 925 global Opts 926 927 set svalues [${win} view get] 928 set bvalues [${win} view bbox] 929 930 set framename [winfo parent ${win}] 931 if {$framename == "."} {return} 932 933 set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}] 934 set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}] 935 936 set wwidth [winfo width ${framename}.xscroll.bar] ;# horizontal scrollbar 937 set wheight [winfo height ${framename}.yscroll.bar] ;# vertical scrollbar 938 939 # Note that adding 0.0 here forces floating-point 940 941 set xscale [expr {(0.0 + $wwidth) / $bwidth}] 942 set yscale [expr {(0.0 + $wheight) / $bheight}] 943 944 set xa [expr {$xscale * ([lindex $svalues 0] - [lindex $bvalues 0]) }] 945 set xb [expr {$xscale * ([lindex $svalues 2] - [lindex $bvalues 0]) }] 946 set ya [expr {$yscale * ([lindex $svalues 1] - [lindex $bvalues 1]) }] 947 set yb [expr {$yscale * ([lindex $svalues 3] - [lindex $bvalues 1]) }] 948 949 # Magic's Y axis is inverted with respect to X11 window coordinates 950 set ya [expr { $wheight - $ya }] 951 set yb [expr { $wheight - $yb }] 952 953 set swidth [expr {int($Opts(scale) * 13)}] 954 set slength [expr {$swidth + 2}] 955 956 ${framename}.xscroll.bar coords slider $xa 2 $xb $slength 957 ${framename}.yscroll.bar coords slider 2 $ya $slength $yb 958 959 set xb [expr { 1 + ($xa + $xb) / 2 }] 960 set xa [expr { $xb - 2 }] 961 ${framename}.xscroll.bar coords centre $xa 4 $xb $swidth 962 963 set yb [expr { 1 + ($ya + $yb) / 2 }] 964 set ya [expr { $yb - 2 }] 965 ${framename}.yscroll.bar coords centre 4 $ya $swidth $yb 966} 967 968# Procedure to update scrollbars in response to an internal command 969# "view" calls "view", so avoid infinite recursion. 970 971proc magic::scrollupdate {win} { 972 973 if {[info level] <= 1} { 974 975 # For NULL window, find current window 976 if {$win == {}} { 977 set win [magic::windownames] 978 } 979 980 # Make sure we're not a 3D window, which doesn't take window commands 981 # This is only necessary because the 3D window declares a "view" 982 # command, too. 983 984 if {$win != [magic::windownames wind3d]} { 985 magic::setscrollvalues $win 986 } 987 } 988} 989 990# scrollview: update the magic display to match the 991# scrollbar positions. 992 993proc magic::scrollview { w win orient } { 994 global scale 995 set v1 $scale($orient,origin) 996 set v2 $scale($orient,update) 997 set delta [expr {$v2 - $v1}] 998 999 set bvalues [${win} view bbox] 1000 set wvalues [${win} windowpositions] 1001 1002 # Note that adding 0.000 in expression forces floating-point 1003 1004 if {"$orient" == "x"} { 1005 1006 set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}] 1007 set wwidth [expr {0.000 + [lindex $wvalues 2] - [lindex $wvalues 0]}] 1008 set xscale [expr {$bwidth / $wwidth}] 1009 ${win} scroll e [expr {$delta * $xscale}]i 1010 1011 } else { 1012 1013 set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}] 1014 set wheight [expr {0.000 + [lindex $wvalues 3] - [lindex $wvalues 1]}] 1015 set yscale [expr {$bheight / $wheight}] 1016 ${win} scroll s [expr {$delta * $yscale}]i 1017 } 1018} 1019 1020# setscroll: get the current cursor position and save it as a 1021# reference point. 1022 1023proc magic::setscroll { w v orient } { 1024 global scale 1025 set scale($orient,origin) $v 1026 set scale($orient,update) $v 1027} 1028 1029proc magic::dragscroll { w v orient } { 1030 global scale 1031 set v1 $scale($orient,update) 1032 set scale($orient,update) $v 1033 set delta [expr {$v - $v1}] 1034 1035 if { "$orient" == "x" } { 1036 $w move slider $delta 0 1037 $w move centre $delta 0 1038 } else { 1039 $w move slider 0 $delta 1040 $w move centre 0 $delta 1041 } 1042} 1043 1044# Scrollbar generator for the wrapper window 1045 1046proc magic::makescrollbar { fname orient win } { 1047 global scale 1048 global Glyph 1049 global Opts 1050 1051 set swidth [expr {int($Opts(scale) * 13)}] 1052 1053 set scale($orient,update) 0 1054 set scale($orient,origin) 0 1055 1056 # To be done: add glyphs for the arrows 1057 1058 if { "$orient" == "x" } { 1059 canvas ${fname}.bar -height $swidth -relief sunken -borderwidth 1 1060 button ${fname}.lb -image Glyph(left) -borderwidth 1 \ 1061 -command "${win} scroll left .1 w" 1062 button ${fname}.ub -image Glyph(right) -borderwidth 1 \ 1063 -command "${win} scroll right .1 w" 1064 pack ${fname}.lb -side left 1065 pack ${fname}.bar -fill $orient -expand true -side left 1066 pack ${fname}.ub -side right 1067 } else { 1068 canvas ${fname}.bar -width $swidth -relief sunken -borderwidth 1 1069 button ${fname}.lb -image Glyph(down) -borderwidth 1 \ 1070 -command "${win} scroll down .1 w" 1071 button ${fname}.ub -image Glyph(up) -borderwidth 1 \ 1072 -command "${win} scroll up .1 w" 1073 pack ${fname}.ub 1074 pack ${fname}.bar -fill $orient -expand true 1075 pack ${fname}.lb 1076 } 1077 1078 # Create the bar which controls the scrolling and bind actions to it 1079 ${fname}.bar create rect 2 2 15 15 -fill steelblue -width 0 -tag slider 1080 ${fname}.bar bind slider <Button-1> "magic::setscroll %W %$orient $orient" 1081 ${fname}.bar bind slider <ButtonRelease-1> "magic::scrollview %W $win $orient" 1082 ${fname}.bar bind slider <B1-Motion> "magic::dragscroll %W %$orient $orient" 1083 1084 # Create a small mark in the center of the scrolling rectangle which aids 1085 # in determining how much the window is being scrolled when the full 1086 # scrollbar extends past the window edges. 1087 ${fname}.bar create rect 4 4 $swidth $swidth -fill black -width 0 -tag centre 1088 ${fname}.bar bind centre <Button-1> "magic::setscroll %W %$orient $orient" 1089 ${fname}.bar bind centre <ButtonRelease-1> "magic::scrollview %W $win $orient" 1090 ${fname}.bar bind centre <B1-Motion> "magic::dragscroll %W %$orient $orient" 1091} 1092 1093# Save all and quit. If something bad happens like an attempt to 1094# write cells into an unwriteable directory, then "cellname list modified" 1095# will contain a list of cells, so prompt to quit with the option to cancel. 1096# If there are no remaining modified and unsaved cells, then just exit. 1097# Because cell "(UNNAMED)" is not written by "writeall force", if that is 1098# the only modified cell, then prompt to change its name and save; then quit. 1099 1100proc magic::saveallandquit {} { 1101 magic::promptsave force 1102 set modlist [magic::cellname list modified] 1103 if {$modlist == {}} { 1104 magic::quit -noprompt 1105 } else { 1106 magic::quit 1107 } 1108} 1109 1110# Create the wrapper and open up a layout window in it. 1111 1112proc magic::openwrapper {{cell ""} {framename ""}} { 1113 global lwindow 1114 global owindow 1115 global tk_version 1116 global Glyph 1117 global Opts 1118 global Winopts 1119 1120 # Disallow scrollbars and title caption on windows---we'll do these ourselves 1121 1122 if {$lwindow == 0} { 1123 windowcaption off 1124 windowscrollbars off 1125 windowborder off 1126 } 1127 1128 if {$framename == ""} { 1129 incr lwindow 1130 set framename .layout${lwindow} 1131 } 1132 set winname ${framename}.pane.top.magic 1133 1134 toplevel $framename 1135 tkwait visibility $framename 1136 1137 # Get scale from the TkDefaultFont size, unless Opts(scale) is already 1138 # set. On standard displays, an "M" in the Sans font is usually 10 1139 # pixels wide, and 22 on high resolution displays, so this maps to 1140 # a scale of 1 on standard displays and a scale of 2 on high resolution 1141 # displays. Make sure scale doesn't go to zero or bad things happen. 1142 1143 if [catch {set Opts(scale)}] { 1144 set Opts(scale) [expr {max(1, int([font measure TkDefaultFont M] / 10))}] 1145 } 1146 1147 # Resize the window 1148 if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} { 1149 catch {wm geometry ${framename} $Opts(geometry)} 1150 } 1151 1152 # Create a paned window top--bottom inside the top level window to accomodate 1153 # a resizable command entry window at the bottom. Sashwidth is zero by default 1154 # but is resized by enabling the command entry window. 1155 1156 panedwindow ${framename}.pane -orient vertical -sashrelief groove -sashwidth 6 1157 1158 frame ${framename}.pane.top 1159 frame ${framename}.pane.bot 1160 1161 set layoutframe ${framename}.pane.top 1162 1163 ${framename}.pane add ${framename}.pane.top 1164 ${framename}.pane add ${framename}.pane.bot 1165 ${framename}.pane paneconfigure ${framename}.pane.top -stretch always 1166 ${framename}.pane paneconfigure ${framename}.pane.bot -hide true 1167 1168 pack ${framename}.pane -side top -fill both -expand true 1169 1170 set swidth [expr {int($Opts(scale) * 13)}] 1171 frame ${layoutframe}.xscroll -height $swidth 1172 frame ${layoutframe}.yscroll -width $swidth 1173 1174 magic::makeglyphimages 1175 magic::makescrollbar ${layoutframe}.xscroll x ${winname} 1176 magic::makescrollbar ${layoutframe}.yscroll y ${winname} 1177 button ${layoutframe}.zb -image Glyph(zoom) -borderwidth 1 -command "${winname} zoom 2" 1178 1179 # Add bindings for mouse buttons 2 and 3 to the zoom button 1180 bind ${layoutframe}.zb <Button-3> "${winname} zoom 0.5" 1181 bind ${layoutframe}.zb <Button-2> "${winname} view" 1182 1183 frame ${layoutframe}.titlebar 1184 label ${layoutframe}.titlebar.caption -text "Loaded: none Editing: none Tool: box" \ 1185 -foreground white -background sienna4 -anchor w -padx 15 1186 label ${layoutframe}.titlebar.message -text "" -foreground white \ 1187 -background sienna4 -anchor w -padx 5 1188 label ${layoutframe}.titlebar.pos -text "" -foreground white \ 1189 -background sienna4 -anchor w -padx 5 1190 1191 # Menu buttons 1192 frame ${layoutframe}.titlebar.mbuttons 1193 1194# File 1195 menubutton ${layoutframe}.titlebar.mbuttons.file -text File -relief raised \ 1196 -menu ${layoutframe}.titlebar.mbuttons.file.toolmenu -borderwidth 2 1197# Edit 1198 menubutton ${layoutframe}.titlebar.mbuttons.edit -text Edit -relief raised \ 1199 -menu ${layoutframe}.titlebar.mbuttons.edit.toolmenu -borderwidth 2 1200# Cell 1201 menubutton ${layoutframe}.titlebar.mbuttons.cell -text Cell -relief raised \ 1202 -menu ${layoutframe}.titlebar.mbuttons.cell.toolmenu -borderwidth 2 1203# Window 1204 menubutton ${layoutframe}.titlebar.mbuttons.win -text Window -relief raised \ 1205 -menu ${layoutframe}.titlebar.mbuttons.win.toolmenu -borderwidth 2 1206# Layers 1207 menubutton ${layoutframe}.titlebar.mbuttons.layers -text Layers -relief raised \ 1208 -menu ${layoutframe}.titlebar.mbuttons.layers.toolmenu -borderwidth 2 1209# DRC 1210 menubutton ${layoutframe}.titlebar.mbuttons.drc -text Drc -relief raised \ 1211 -menu ${layoutframe}.titlebar.mbuttons.drc.toolmenu -borderwidth 2 1212# Netlist 1213# menubutton ${layoutframe}.titlebar.mbuttons.netlist -text Neltist -relief raised \ 1214# -menu ${layoutframe}.titlebar.mbuttons.netlist.netlistmenu -borderwidth 2 1215# Help 1216# menubutton ${layoutframe}.titlebar.mbuttons.help -text Help -relief raised \ 1217# -menu ${layoutframe}.titlebar.mbuttons.help.helpmenu -borderwidth 2 1218# Options 1219 menubutton ${layoutframe}.titlebar.mbuttons.opts -text Options -relief raised \ 1220 -menu ${layoutframe}.titlebar.mbuttons.opts.toolmenu -borderwidth 2 1221 pack ${layoutframe}.titlebar.mbuttons.file -side left 1222 pack ${layoutframe}.titlebar.mbuttons.edit -side left 1223 pack ${layoutframe}.titlebar.mbuttons.cell -side left 1224 pack ${layoutframe}.titlebar.mbuttons.win -side left 1225 pack ${layoutframe}.titlebar.mbuttons.layers -side left 1226 pack ${layoutframe}.titlebar.mbuttons.drc -side left 1227# pack ${layoutframe}.titlebar.mbuttons.netlist -side left 1228# pack ${layoutframe}.titlebar.mbuttons.help -side left 1229 pack ${layoutframe}.titlebar.mbuttons.opts -side left 1230 1231 # DRC status button 1232 checkbutton ${layoutframe}.titlebar.drcbutton -text "DRC" -anchor w \ 1233 -borderwidth 2 -variable Opts(drc) \ 1234 -foreground white -background sienna4 -selectcolor green \ 1235 -command [subst { if { \$Opts(drc) } { drc on } else { drc off } }] 1236 1237 magic::openwindow $cell $winname 1238 1239 # Create toolbar frame. Make sure it has the same visual and depth as 1240 # the layout window, so there will be no problem using the GCs from the 1241 # layout window to paint into the toolbar. 1242 frame ${layoutframe}.toolbar \ 1243 -visual "[winfo visual ${winname}] [winfo depth ${winname}]" 1244 1245 # Repaint to magic colors 1246 magic::repaintwrapper ${layoutframe} 1247 1248 grid ${layoutframe}.titlebar -row 0 -column 0 -columnspan 3 -sticky news 1249 grid ${layoutframe}.yscroll -row 1 -column 0 -sticky ns 1250 grid $winname -row 1 -column 1 -sticky news 1251 grid ${layoutframe}.zb -row 2 -column 0 1252 grid ${layoutframe}.xscroll -row 2 -column 1 -sticky ew 1253 # The toolbar is not attached by default 1254 1255 grid rowconfigure ${layoutframe} 1 -weight 1 1256 grid columnconfigure ${layoutframe} 1 -weight 1 1257 1258 grid ${layoutframe}.titlebar.mbuttons -row 0 -column 0 -sticky news 1259 grid ${layoutframe}.titlebar.drcbutton -row 0 -column 1 -sticky news 1260 grid ${layoutframe}.titlebar.caption -row 0 -column 2 -sticky news 1261 grid ${layoutframe}.titlebar.message -row 0 -column 3 -sticky news 1262 grid ${layoutframe}.titlebar.pos -row 0 -column 4 -sticky news 1263 grid columnconfigure ${layoutframe}.titlebar 2 -weight 1 1264 1265 bind $winname <Enter> "focus %W ; set Opts(focus) $framename" 1266 1267 # Note: Tk binding bypasses the event proc, so it is important to 1268 # set the current point; otherwise, the cursor will report the 1269 # wrong position and/or the wrong window. HOWEVER we should wrap 1270 # this command with the "bypass" command such that it does not 1271 # reset any current input redirection to the terminal. 1272 1273 bind ${winname} <Motion> "*bypass setpoint %x %y ${winname}; \ 1274 magic::cursorview ${winname}" 1275 1276 set Winopts(${framename},toolbar) 1 1277 set Winopts(${framename},cmdentry) 0 1278 1279# ################################# 1280# File 1281# ################################# 1282 set m [menu ${layoutframe}.titlebar.mbuttons.file.toolmenu -tearoff 0] 1283 $m add command -label "Open..." -command {magic::promptload magic} 1284 # $m add command -label "Save" -command {magic::save } 1285 $m add command -label "Save..." -command {magic::promptsave magic} 1286 # $m add command -label "Save as..." -command {echo "not implemented"} 1287 # $m add command -label "Save selection..." -command {echo "not implemented"} 1288 $m add separator 1289 $m add command -label "Flush changes" -command {magic::flush} 1290 $m add separator 1291 # $m add command -label "Read CIF" -command {magic::promptload cif} 1292 $m add command -label "Read GDS" -command {magic::promptload gds} 1293 # $m add separator 1294 # $m add command -label "Write CIF" -command {magic::promptsave cif} 1295 $m add command -label "Write GDS" -command {magic::promptsave gds} 1296 # $m add separator 1297 # $m add command -label "Print..." -command {echo "not implemented"} 1298 $m add separator 1299 $m add command -label "Save All and Quit" -command {magic::saveallandquit} 1300 $m add command -label "Quit" -command {magic::quit} 1301 1302# ################################# 1303# Edit 1304# ################################# 1305 1306 set m [menu ${layoutframe}.titlebar.mbuttons.edit.toolmenu -tearoff 0] 1307 # $m add command -label "Cut" -command {echo "not implemented"} 1308 # $m add command -label "Copy" -command {echo "not implemented"} 1309 # $m add command -label "Paste" -command {echo "not implemented"} 1310 $m add command -label "Delete" -command {delete} 1311 $m add separator 1312 $m add command -label "Select Area" -command {select area} 1313 $m add command -label "Select Clear" -command {select clear} 1314 $m add separator 1315 $m add command -label "Undo" -command {magic::undo} 1316 $m add command -label "Redo" -command {magic::redo} 1317 # $m add command -label "Repeat Last" -command {echo "not implemented"} 1318 $m add separator 1319 $m add command -label "Rotate 90 degree" -command {magic::clock} 1320 $m add command -label "Mirror Up/Down" -command {magic::upsidedown} 1321 $m add command -label "Mirror Left/Right" -command {magic::sideways} 1322 $m add separator 1323 $m add command -label "Move Right" -command {move right 1} 1324 $m add command -label "Move Left" -command {move left 1} 1325 $m add command -label "Move Up" -command {move up 1} 1326 $m add command -label "Move Down" -command {move down 1} 1327 $m add separator 1328 $m add command -label "Stretch Right" -command {stretch right 1} 1329 $m add command -label "Stretch Left" -command {stretch left 1} 1330 $m add command -label "Stretch Up" -command {stretch up 1} 1331 $m add command -label "Stretch Down" -command {stretch down 1} 1332 $m add separator 1333 $m add command -label "Text ..." \ 1334 -command [subst {magic::update_texthelper; \ 1335 wm deiconify .texthelper ; raise .texthelper}] 1336 1337# ################################# 1338# Cell 1339# ################################# 1340 set m [menu ${layoutframe}.titlebar.mbuttons.cell.toolmenu -tearoff 0] 1341 $m add command -label "New..." -command {magic::prompt_dialog new} 1342 $m add command -label "Save as..." -command {magic::prompt_dialog save} 1343 $m add command -label "Select" -command {magic::select cell} 1344 $m add command -label "Place Instance" -command {magic::promptload getcell} 1345 # $m add command -label "Rename" -command {echo "not implemented"} 1346 $m add separator 1347 $m add command -label "Down hierarchy" -command {magic::pushstack} 1348 $m add command -label "Up hierarchy" -command {magic::popstack} 1349 $m add separator 1350 $m add command -label "Edit" -command {magic::edit} 1351 $m add separator 1352 $m add command -label "Delete" -command \ 1353 {magic::cellname delete [magic::cellname list window]} 1354 $m add separator 1355 $m add command -label "Expand Toggle" -command {magic::expand toggle} 1356 $m add command -label "Expand" -command {magic::expand} 1357 $m add command -label "Unexpand" -command {magic::unexpand} 1358 $m add separator 1359 $m add command -label "Lock Cell" -command {magic::instance lock} 1360 $m add command -label "Unlock Cell" -command {magic::instance unlock} 1361 1362# ################################# 1363# Window 1364# ################################# 1365 set m [menu ${layoutframe}.titlebar.mbuttons.win.toolmenu -tearoff 0] 1366 $m add command -label "Clone" -command \ 1367 {magic::openwrapper [magic::cellname list window]} 1368 $m add command -label "New" -command "magic::openwrapper" 1369 $m add command -label "Set Editable" -command \ 1370 "pushbox ; select top cell ; edit ; popbox" 1371 $m add command -label "Close" -command "closewrapper ${framename}" 1372 $m add separator 1373 $m add command -label "Full View" -command {magic::view} 1374 $m add command -label "Redraw" -command {magic::redraw} 1375 $m add command -label "Zoom Out" -command {magic::zoom 2} 1376 $m add command -label "Zoom In" -command {magic::zoom 0.5} 1377 $m add command -label "Zoom Box" -command {magic::findbox zoom} 1378 $m add separator 1379 $m add command -label "Grid on" -command {magic::grid on} 1380 $m add command -label "Grid off" -command {magic::grid off} 1381 $m add command -label "Snap-to-grid on" -command {magic::snap on} 1382 $m add command -label "Snap-to-grid off" -command {magic::snap off} 1383 $m add command -label "Measure box" -command {magic::box } 1384 $m add separator 1385 $m add command -label "Set grid 0.05um" -command {magic::grid 0.05um} 1386 $m add command -label "Set grid 0.10um" -command {magic::grid 0.10um} 1387 $m add command -label "Set grid 0.50um" -command {magic::grid 0.50um} 1388 $m add command -label "Set grid 1.00um" -command {magic::grid 1.00um} 1389 $m add command -label "Set grid 5.00um" -command {magic::grid 5.00um} 1390 $m add command -label "Set grid 10.0um" -command {magic::grid 10.0um} 1391 # $m add command -label "Set grid ..." -command {echo "not implemented"} 1392 1393# ################################# 1394# Layers 1395# ################################# 1396 set m [menu ${layoutframe}.titlebar.mbuttons.layers.toolmenu -tearoff 0] 1397 $m add command -label "Protect Base Layers" -command {magic::tech revert} 1398 $m add command -label "Unlock Base Layers" -command {magic::tech unlock *} 1399 $m add separator 1400 $m add command -label "Clear Feedback" -command {magic::feedback clear} 1401 $m add separator 1402 1403# ################################# 1404# DRC 1405# ################################# 1406 set m [menu ${layoutframe}.titlebar.mbuttons.drc.toolmenu -tearoff 0] 1407 # $m add command -label "DRC On" -command {drc on} 1408 # $m add command -label "DRC Off" -command {drc off} 1409 # $m add separator 1410 $m add command -label "DRC update" -command {drc check; drc why} 1411 $m add command -label "DRC report" -command {drc why} 1412 $m add command -label "DRC Find next error" -command {drc find; findbox zoom} 1413 $m add separator 1414 $m add command -label "DRC Fast" -command {drc style drc(fast)} 1415 $m add command -label "DRC Complete" -command {drc style drc(full)} 1416 1417 set m [menu ${layoutframe}.titlebar.mbuttons.opts.toolmenu -tearoff 0] 1418 $m add check -label "Toolbar" -variable Winopts(${framename},toolbar) \ 1419 -command [subst {if { \$Winopts(${framename},toolbar) } { \ 1420 magic::maketoolbar ${layoutframe} ; \ 1421 grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new ; \ 1422 } else { \ 1423 grid forget ${layoutframe}.toolbar } }] 1424 1425 $m add check -label "Toolbar Hide Locked" \ 1426 -variable Opts(hidelocked) \ 1427 -command "magic::maketoolbar ${layoutframe}" 1428 1429 .winmenu add radio -label ${framename} -variable Opts(target) -value ${winname} 1430 if {$tk_version >= 8.5} { 1431 $m add check -label "Cell Manager" -variable Opts(cellmgr) \ 1432 -command [subst { magic::cellmanager create; \ 1433 if { \$Opts(cellmgr) } { \ 1434 wm deiconify .cellmgr ; raise .cellmgr \ 1435 } else { \ 1436 wm withdraw .cellmgr } }] 1437 .winmenu entryconfigure last -command ".cellmgr.target.list configure \ 1438 -text ${framename}" 1439 } 1440 if {$tk_version >= 8.5} { 1441 $m add check -label "Library Manager" -variable Opts(libmgr) \ 1442 -command [subst { magic::libmanager create; \ 1443 if { \$Opts(libmgr) } { \ 1444 wm deiconify .libmgr ; raise .libmgr \ 1445 } else { \ 1446 wm withdraw .libmgr } }] 1447 .winmenu entryconfigure last -command ".libmgr.target.list configure \ 1448 -text ${framename}" 1449 } 1450 $m add check -label "Tech Manager" -variable Opts(techmgr) \ 1451 -command [subst { magic::techmanager create; \ 1452 if { \$Opts(techmgr) } { \ 1453 wm deiconify .techmgr ; raise .techmgr \ 1454 } else { \ 1455 wm withdraw .techmgr } }] 1456 1457 $m add check -label "DRC Manager" -variable Opts(drcmgr) \ 1458 -command [subst { magic::drcmanager create; \ 1459 if { \$Opts(drcmgr) } { \ 1460 wm deiconify .drcmgr ; raise .drcmgr \ 1461 } else { \ 1462 wm withdraw .drcmgr } }] 1463 1464 $m add check -label "Netlist Window" -variable Opts(netlist) \ 1465 -command [subst { if { \[windownames netlist\] != {}} { \ 1466 set Opts(netlist) 0 ; closewindow \[windownames netlist\] \ 1467 } else { \ 1468 set Opts(netlist) 1 ; specialopen netlist \ 1469 } }] 1470 1471 $m add check -label "Colormap Window" -variable Opts(colormap) \ 1472 -command [subst { if { \[windownames color\] != {}} { \ 1473 set Opts(colormap) 0 ; closewindow \[windownames color\] \ 1474 } else { \ 1475 set Opts(colormap) 1 ; specialopen color \ 1476 } }] 1477 1478 $m add check -label "3D Display" -variable Opts(wind3d) \ 1479 -command [subst { if { \[windownames wind3d\] != {}} { \ 1480 set Opts(wind3d) 0 ; .render.magic closewindow ; \ 1481 destroy .render \ 1482 } else { \ 1483 set Opts(wind3d) 1 ; \ 1484 magic::render3d \[${winname} cellname list window\] \ 1485 } }] 1486 1487 $m add check -label "Window Command Entry" \ 1488 -variable Winopts(${framename},cmdentry) \ 1489 -command [subst { if { \$Winopts(${framename},cmdentry) } { \ 1490 addcommandentry $framename \ 1491 } else { \ 1492 deletecommandentry $framename } }] 1493 1494 $m add check -label "Crosshair" \ 1495 -variable Opts(crosshair) \ 1496 -command {if {$Opts(crosshair) == 0} {crosshair off}} 1497 1498 catch {addmazehelper $m} 1499 1500 # Set the default view 1501 1502 update idletasks 1503 ${winname} magic::view 1504 1505 magic::captions 1506 1507 # If the toolbar is turned on, invoke the toolbar button 1508 if { $Winopts(${framename},toolbar) == 1} { 1509 magic::maketoolbar ${layoutframe} 1510 grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new 1511 } 1512 1513 # Remove "open" and "close" macros so they don't generate non-GUI 1514 # windows or (worse) blow away the window inside the GUI frame 1515 1516 if {[magic::macro list o] == "openwindow"} { 1517 magic::macro o \ 1518 "incr owindow ;\ 1519 set rpt \[cursor screen\] ;\ 1520 set rptx \[lindex \$rpt 0\] ;\ 1521 set rpty \[lindex \$rpt 1\] ;\ 1522 set Winopts(.owindow\$owindow,geometry) 500x500+\$rptx+\$rpty ;\ 1523 openwrapper \[\$Opts(focus)*.magic cellname list window\] \ 1524 .owindow\$owindow ;\ 1525 .owindow\$owindow*.magic view \[box values\]" 1526 } 1527 if {[magic::macro list O] == "closewindow"} { 1528 magic::macro O "closewrapper \$Opts(focus)" 1529 } 1530 1531 # Make sure that closing from the window manager is equivalent to 1532 # the command "closewrapper" 1533 wm protocol ${framename} WM_DELETE_WINDOW "closewrapper ${framename}" 1534 1535 # If the variable $Opts(callback) is defined, then attempt to execute it. 1536 catch {eval $Opts(callback)} 1537 1538 # If the variable $Winopts(callback) is defined, then attempt to execute it. 1539 catch {eval $Winopts(${framename}, callback)} 1540 1541 # Since one purpose of the window callback is to customize the menus, 1542 # run the automatic generation of accelerator key text at the end. 1543 # This can be subverted by setting Opts(autobuttontext) to 0, e.g., 1544 # to put it at the top of the Winopts callback and then generate 1545 # override values for specific buttons. 1546 if {$Opts(autobuttontext)} { 1547 catch {magic::button_auto_bind_text $layoutframe} 1548 } 1549 return ${winname} 1550} 1551 1552# Delete the wrapper and the layout window in it. 1553 1554proc magic::closewrapper { framename } { 1555 global tk_version 1556 global Opts 1557 1558 # Remove this window from the target list in .winmenu 1559 # (used by, e.g., cellmanager) 1560 1561 set layoutframe ${framename}.pane.top 1562 if { $Opts(target) == "${layoutframe}.magic" } { 1563 set Opts(target) "default" 1564 if {$tk_version >= 8.5} { 1565 if {![catch {wm state .cellmgr}]} { 1566 .cellmgr.target.list configure -text "default" 1567 } 1568 } 1569 } 1570 1571 set idx [.winmenu index $framename] 1572 .winmenu delete $idx 1573 1574 ${layoutframe}.magic magic::closewindow 1575 destroy $framename 1576} 1577 1578# This procedure adds a command-line entry window to the bottom of 1579# a wrapper window (rudimentary functionality---incomplete) 1580 1581proc magic::addcommandentry { framename } { 1582 set commandframe ${framename}.pane.bot 1583 if {![winfo exists ${commandframe}.eval]} { 1584 tkshell::YScrolled_Text ${commandframe}.eval -height 5 1585 tkshell::MakeEvaluator ${commandframe}.eval.text \ 1586 "${framename}>" ${framename}.pane.top.magic 1587 pack ${commandframe}.eval -side top -fill both -expand true 1588 ${framename}.pane paneconfigure ${framename}.pane.bot -stretch never 1589 ${framename}.pane paneconfigure ${framename}.pane.bot -minsize 50 1590 } 1591 set entercmd [bind ${framename}.pane.top.magic <Enter>] 1592 set bindstr "$entercmd ; macro XK_colon \"set Opts(redirect) 1;\ 1593 focus ${commandframe}.eval.text\";\ 1594 alias puts tkshell::PutsTkShell" 1595 bind ${commandframe}.eval <Enter> \ 1596 "focus ${commandframe}.eval.text ; set Opts(focus) $framename ;\ 1597 catch {unset Opts(redirect)}" 1598 bind ${framename}.pane.top.magic <Enter> $bindstr 1599 # Make command entry window visible 1600 ${framename}.pane paneconfigure ${framename}.pane.bot -hide false 1601} 1602 1603# Remove the command entry window from the bottom of a frame. 1604 1605proc magic::deletecommandentry { framename } { 1606 set commandframe ${framename}.pane.bot 1607 ::grid forget ${commandframe}.eval 1608 # Remove the last bindings for <Enter> 1609 set bindstr [bind ${framename}.pane.top.magic <Enter>] 1610 set i [string first "; macro" $bindstr] 1611 set bindstr [string range $bindstr 0 $i-1] 1612 bind ${framename}.pane.top.magic <Enter> $bindstr 1613 # Restore the keybinding for colon 1614 imacro XK_colon ":" 1615 # Restore the alias for "puts" 1616 alias puts ::tkcon_puts 1617 # Make command entry window invisible 1618 ${framename}.pane paneconfigure ${framename}.pane.bot -hide true 1619} 1620 1621namespace import magic::openwrapper 1622puts "Use openwrapper to create a new GUI-based layout window" 1623namespace import magic::closewrapper 1624puts "Use closewrapper to remove a new GUI-based layout window" 1625 1626# Create a simple wrapper for the 3D window. . . this can be 1627# greatly expanded upon. 1628 1629proc magic::render3d {{cell ""}} { 1630 global Opts 1631 1632 toplevel .render 1633 tkwait visibility .render 1634 magic::specialopen wind3d $cell .render.magic 1635 .render.magic cutbox box 1636 set Opts(cutbox) 1 1637 wm protocol .render WM_DELETE_WINDOW "set Opts(wind3d) 0 ; \ 1638 .render.magic closewindow ; destroy .render" 1639 1640 frame .render.title 1641 pack .render.title -expand true -fill x -side top 1642 checkbutton .render.title.cutbox -text "Cutbox" -variable Opts(cutbox) \ 1643 -foreground white -background sienna4 -anchor w -padx 15 \ 1644 -command [subst { if { \$Opts(cutbox) } { .render.magic cutbox box \ 1645 } else { \ 1646 .render.magic cutbox none } }] 1647 1648 if {$cell == ""} {set cell default} 1649 label .render.title.msg -text "3D Rendering window Cell: $cell" \ 1650 -foreground white -background sienna4 -anchor w -padx 15 1651 pack .render.title.cutbox -side left 1652 pack .render.title.msg -side right -fill x -expand true 1653 pack .render.magic -expand true -fill both -side bottom 1654 bind .render.magic <Enter> {focus %W} 1655} 1656 1657