# This is the "Magic wrapper". # Its main purpose is to redefine the "openwindow" command in magic so that # opening a new window creates a window wrapped by a GUI interface. # # Written by Tim Edwards, August 23, 2002. # revision A: proof-of-concept. Add whatever you want to this basic wrapper. # revision B: Adds Tk scrollbars and caption # revision C: Adds a layer manager toolbar on the left side # revision D: Adds a menubar on top with cell and tech manager tools global lwindow global tk_version global Glyph global Opts global Winopts set tk_version $::tk_version # Simple console commands (like TkCon, but much simpler) if {[lsearch [namespace children] ::tkshell] < 0} { catch {source ${CAD_ROOT}/magic/tcl/tkshell.tcl} } proc magic::makeglyphimages {} { global Opts global Glyph global CAD_ROOT # Check if glyphs exist---don't need to make them more than once if {![catch {set Glyph(up)}]} {return} # Glyph images set gsize [expr {int($Opts(scale) * 13)}] set gscale [expr {int($Opts(scale))}] image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/up.gif image create photo Glyph(up) -width $gsize -height $gsize Glyph(up) copy stdglyph -zoom $gscale image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/down.gif image create photo Glyph(down) -width $gsize -height $gsize Glyph(down) copy stdglyph -zoom $gscale image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/left.gif image create photo Glyph(left) -width $gsize -height $gsize Glyph(left) copy stdglyph -zoom $gscale image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/right.gif image create photo Glyph(right) -width $gsize -height $gsize Glyph(right) copy stdglyph -zoom $gscale image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/zoom.gif image create photo Glyph(zoom) -width $gsize -height $gsize Glyph(zoom) copy stdglyph -zoom $gscale image create bitmap Glyph(lock) \ -file ${CAD_ROOT}/magic/tcl/bitmaps/lock.xbm \ -background gray80 -foreground steelblue4] } # Menu button callback functions proc magic::promptload {type} { global CAD_ROOT switch $type { cif { set Layoutfilename [ tk_getOpenFile -filetypes \ {{CIF {.cif {.cif}}} {"All files" {*}}}] if {$Layoutfilename != ""} { set cifname [file tail [file root $Layoutfilename]] magic::cellname create cif_temp magic::load cif_temp magic::cif read [file root $Layoutfilename] set childcells [magic::cellname list children cif_temp] magic::load [lindex $childcells 0] magic::cellname delete cif_temp -noprompt if {[llength $childcells] > 1} { puts stdout "Cells read from GDS file: $childcells" } } } gds { set Layoutfilename [ tk_getOpenFile -filetypes \ {{GDS {.gds .strm .cal {.gds .strm .cal}}} {"All files" {*}}}] if {$Layoutfilename != ""} { set origlist [magic::cellname list top] magic::gds read [file root $Layoutfilename] set newlist [magic::cellname list top] # Find entries in newlist that are not in origlist. # If there's only one, load it into the window. set newtopcells {} foreach n $newlist { if {[lsearch $origlist $n] < 0} { lappend newtopcells $n } } if {[llength $newtopcells] == 1} { magic::load [lindex $newtopcells 0] } elseif {[llength $newtopcells] != 0} { puts stdout "Top-level cells read from GDS file: $newtopcells" } } } magic { set Layoutfilename [ tk_getOpenFile -filetypes \ {{Magic {.mag {.mag}}} {"All files" {*}}}] if {$Layoutfilename != ""} { magic::load [file root $Layoutfilename] } } getcell { set Layoutfilename [ tk_getOpenFile -filetypes \ {{Magic {.mag {.mag}}} {"All files" {*}}}] if {$Layoutfilename != ""} { set fdir [file dirname $Layoutfilename] set lidx [lsearch [path search] $fdir] if {$lidx < 0} {path search +$fdir} magic::getcell [file tail $Layoutfilename] # Append path to cell search path if it's not there already if {[string index $Layoutfilename 0] != "/"} { set $Layoutfilename "./$Layoutfilename" } set sidx [string last "/" $Layoutfilename] if {$sidx > 0} { set cellpath [string range $Layoutfilename 0 $sidx] magic::path cell +$cellpath } } } } } proc magic::promptsave {type} { global CAD_ROOT switch $type { cif { set Layoutfilename [ tk_getSaveFile -filetypes \ {{CIF {.cif {.cif}}} {"All files" {*}}}] if {$Layoutfilename != ""} { magic::cif write $Layoutfilename } } gds { set Layoutfilename [ tk_getSaveFile -filetypes \ {{GDS {.gds .strm .cal {.gds .strm .cal}}} {"All files" {*}}}] if {$Layoutfilename != ""} { magic::gds write $Layoutfilename } } force - magic { set CellList [ magic::cellname list window ] if {[lsearch $CellList "(UNNAMED)"] >= 0} { set Layoutfilename [ tk_getSaveFile -filetypes \ {{Magic {.mag {.mag}}} {"All files" {*}}} \ -title "Save cell (UNNAMED) as:" ] if {$Layoutfilename != ""} { set cellpath [file dirname $Layoutfilename] if {$cellpath == [pwd]} { set Layoutfilename [file tail $Layoutfilename] } else { magic::path cell +$cellpath } magic::save $Layoutfilename } } if {$type == "force"} { magic::writeall force } else { magic::writeall } } } } # Window to prompt for a new cell proc magic::prompt_dialog { type } { global Opts if {[catch {toplevel .dialog}]} { foreach child [winfo children .dialog] { destroy $child } } frame .dialog.titlebar frame .dialog.text frame .dialog.bbar switch $type { new { label .dialog.titlebar.title -text "Create new cell" -foreground blue button .dialog.bbar.okay -text "Okay" -command {load $Opts(cell_name); \ lower .dialog} set Opts(cell_name) "(UNNAMED)" } save { label .dialog.titlebar.title -text "Save cell as..." -foreground blue button .dialog.bbar.okay -text "Okay" -command {save $Opts(cell_name); \ lower .dialog} set Opts(cell_name) [cellname list window] } } pack .dialog.titlebar.title label .dialog.text.tlabel -text "Cell name:" -foreground brown entry .dialog.text.tentry -background white -textvariable Opts(cell_name) pack .dialog.text.tlabel -side left pack .dialog.text.tentry -side left button .dialog.bbar.cancel -text "Cancel" -command "lower .dialog" pack .dialog.bbar.okay -side left pack .dialog.bbar.cancel -side right pack .dialog.titlebar -side top -ipadx 2 -ipady 2 pack .dialog.text -side top -fill both -expand true pack .dialog.bbar -side top -fill x -ipadx 5 bind .dialog.text.tentry {.dialog.bbar.okay invoke} raise .dialog } # Callback functions used by the DRC. proc magic::drcupdate { option } { global Opts if {[info level] <= 1} { switch $option { on {set Opts(drc) 1} off {set Opts(drc) 0} } } } proc magic::drcstate { status } { set winlist [*bypass windownames layout] foreach lwin $winlist { set framename [winfo parent $lwin] if {$framename == "."} {return} switch $status { idle { set dct [*bypass drc list count total] if {$dct > 0} { ${framename}.titlebar.drcbutton configure -selectcolor red } else { ${framename}.titlebar.drcbutton configure -selectcolor green } ${framename}.titlebar.drcbutton configure -text "DRC=$dct" } busy { ${framename}.titlebar.drcbutton configure -selectcolor yellow } } } } # Create the menu of windows. This is kept separate from the cell manager, # and linked into it by the "clone" command. menu .winmenu -tearoff 0 proc magic::setgrid {gridsize} { set techlambda [magic::tech lambda] set tech1 [lindex $techlambda 1] set tech0 [lindex $techlambda 0] set tscale [expr {$tech1 / $tech0}] set lambdaout [expr {[magic::cif scale output] * $tscale}] set gridlambda [expr {$gridsize/$lambdaout}] magic::grid ${gridlambda}l magic::snap on } # Technology manager callback functions proc magic::techparseunits {} { set techlambda [magic::tech lambda] set tech1 [lindex $techlambda 1] set tech0 [lindex $techlambda 0] set target0 [.techmgr.lambda1.lval0 get] set target1 [.techmgr.lambda1.lval1 get] set newval0 [expr {$target0 * $tech0}] set newval1 [expr {$target1 * $tech1}] magic::scalegrid $newval1 $newval0 magic::techmanager update } # The technology manager proc magic::maketechmanager { mgrpath } { toplevel $mgrpath wm withdraw $mgrpath frame ${mgrpath}.title label ${mgrpath}.title.tlab -text "Technology: " menubutton ${mgrpath}.title.tname -text "(none)" -foreground red3 \ -menu ${mgrpath}.title.tname.menu label ${mgrpath}.title.tvers -text "" -foreground blue label ${mgrpath}.subtitle -text "" -foreground sienna4 frame ${mgrpath}.lambda0 label ${mgrpath}.lambda0.llab -text "Microns per lambda (CIF): " label ${mgrpath}.lambda0.lval -text "1" -foreground blue frame ${mgrpath}.lambda1 label ${mgrpath}.lambda1.llab -text "Internal units per lambda: " entry ${mgrpath}.lambda1.lval0 -foreground red3 -background white -width 3 label ${mgrpath}.lambda1.ldiv -text " / " entry ${mgrpath}.lambda1.lval1 -foreground red3 -background white -width 3 frame ${mgrpath}.cif0 label ${mgrpath}.cif0.llab -text "CIF input style: " menubutton ${mgrpath}.cif0.lstyle -text "" -foreground blue \ -menu ${mgrpath}.cif0.lstyle.menu label ${mgrpath}.cif0.llab2 -text " Microns/lambda=" label ${mgrpath}.cif0.llambda -text "" -foreground red3 frame ${mgrpath}.cif1 label ${mgrpath}.cif1.llab -text "CIF output style: " menubutton ${mgrpath}.cif1.lstyle -text "" -foreground blue \ -menu ${mgrpath}.cif1.lstyle.menu label ${mgrpath}.cif1.llab2 -text " Microns/lambda=" label ${mgrpath}.cif1.llambda -text "" -foreground red3 frame ${mgrpath}.extract label ${mgrpath}.extract.llab -text "Extract style: " menubutton ${mgrpath}.extract.lstyle -text "" -foreground blue \ -menu ${mgrpath}.extract.lstyle.menu frame ${mgrpath}.drc label ${mgrpath}.drc.llab -text "DRC style: " menubutton ${mgrpath}.drc.lstyle -text "" -foreground blue \ -menu ${mgrpath}.drc.lstyle.menu pack ${mgrpath}.title.tlab -side left pack ${mgrpath}.title.tname -side left pack ${mgrpath}.title.tvers -side left pack ${mgrpath}.lambda0.llab -side left pack ${mgrpath}.lambda0.lval -side left pack ${mgrpath}.lambda1.llab -side left pack ${mgrpath}.lambda1.lval0 -side left pack ${mgrpath}.lambda1.ldiv -side left pack ${mgrpath}.lambda1.lval1 -side left pack ${mgrpath}.cif0.llab -side left pack ${mgrpath}.cif0.lstyle -side left pack ${mgrpath}.cif0.llab2 -side left pack ${mgrpath}.cif0.llambda -side left pack ${mgrpath}.cif1.llab -side left pack ${mgrpath}.cif1.lstyle -side left pack ${mgrpath}.cif1.llab2 -side left pack ${mgrpath}.cif1.llambda -side left pack ${mgrpath}.extract.llab -side left pack ${mgrpath}.extract.lstyle -side left pack ${mgrpath}.drc.llab -side left pack ${mgrpath}.drc.lstyle -side left pack ${mgrpath}.title -side top -fill x pack ${mgrpath}.subtitle -side top -fill x pack ${mgrpath}.lambda0 -side top -fill x pack ${mgrpath}.lambda1 -side top -fill x pack ${mgrpath}.cif0 -side top -fill x pack ${mgrpath}.cif1 -side top -fill x pack ${mgrpath}.extract -side top -fill x bind ${mgrpath}.lambda1.lval0 magic::techparseunits bind ${mgrpath}.lambda1.lval1 magic::techparseunits #Withdraw the window when the close button is pressed wm protocol ${mgrpath} WM_DELETE_WINDOW "set Opts(techmgr) 0 ; wm withdraw ${mgrpath}" } # Generate the cell manager catch {source ${CAD_ROOT}/magic/tcl/cellmgr.tcl} # Generate the library manager catch {source ${CAD_ROOT}/magic/tcl/libmgr.tcl} # Generate the DRC manager catch {source ${CAD_ROOT}/magic/tcl/drcmgr.tcl} # Generate the text helper catch {source ${CAD_ROOT}/magic/tcl/texthelper.tcl} # Create or redisplay the technology manager proc magic::techmanager {{option "update"}} { global CAD_ROOT if {[catch {wm state .techmgr}]} { if {$option == "create"} { magic::maketechmanager .techmgr } else { return } } elseif { $option == "create"} { return } if {$option == "create"} { menu .techmgr.title.tname.menu -tearoff 0 menu .techmgr.cif0.lstyle.menu -tearoff 0 menu .techmgr.cif1.lstyle.menu -tearoff 0 menu .techmgr.extract.lstyle.menu -tearoff 0 menu .techmgr.drc.lstyle.menu -tearoff 0 } if {$option == "init"} { .techmgr.title.tname.menu delete 0 end .techmgr.cif0.lstyle.menu delete 0 end .techmgr.cif1.lstyle.menu delete 0 end .techmgr.extract.lstyle.menu delete 0 end .techmgr.drc.lstyle.menu delete 0 end } if {$option == "init" || $option == "create"} { set tlist [magic::cif listall istyle] foreach i $tlist { .techmgr.cif0.lstyle.menu add command -label $i -command \ "magic::cif istyle $i ; \ magic::techmanager update" } set tlist [magic::cif listall ostyle] foreach i $tlist { .techmgr.cif1.lstyle.menu add command -label $i -command \ "magic::cif ostyle $i ; \ magic::techmanager update" } set tlist [magic::extract listall style] foreach i $tlist { .techmgr.extract.lstyle.menu add command -label $i -command \ "magic::extract style $i ; \ magic::techmanager update" } set tlist [magic::drc listall style] foreach i $tlist { .techmgr.drc.lstyle.menu add command -label $i -command \ "magic::drc style $i ; \ magic::techmanager update" } set dirlist [subst [magic::path sys]] set tlist {} foreach i $dirlist { lappend tlist [glob -nocomplain ${i}/*.tech] lappend tlist [glob -nocomplain ${i}/*.tech27] } foreach i [join $tlist] { set j [file tail [file rootname ${i}]] .techmgr.title.tname.menu add command -label $j -command \ "magic::tech load $j ; \ magic::techmanager update" } } set techlambda [magic::tech lambda] set tech1 [lindex $techlambda 1] set tech0 [lindex $techlambda 0] set tscale [expr {$tech1 / $tech0}] .techmgr.title.tname configure -text [magic::tech name] set techstuff [magic::tech version] .techmgr.title.tvers configure -text "(version [lindex $techstuff 0])" .techmgr.subtitle configure -text [lindex $techstuff 1] set lotext [format "%g" [expr {[magic::cif scale output] * $tscale}]] .techmgr.lambda0.lval configure -text $lotext .techmgr.cif0.lstyle configure -text [magic::cif list istyle] set litext [format "%g" [expr {[magic::cif scale input] * $tscale}]] .techmgr.cif0.llambda configure -text $litext .techmgr.cif1.lstyle configure -text [magic::cif list ostyle] .techmgr.cif1.llambda configure -text $lotext .techmgr.extract.lstyle configure -text [magic::extract list style] .techmgr.drc.lstyle configure -text [magic::drc list style] .techmgr.lambda1.lval0 delete 0 end .techmgr.lambda1.lval1 delete 0 end .techmgr.lambda1.lval0 insert end $tech1 .techmgr.lambda1.lval1 insert end $tech0 } proc magic::captions {{subcommand {}}} { global Opts if {$subcommand != {} && $subcommand != "writeable" && $subcommand != "load"} { return } set winlist [magic::windownames layout] foreach winpath $winlist { set framename [winfo parent $winpath] set caption [$winpath windowcaption] set subcaption1 [lindex $caption 0] set techname [tech name] if {[catch {set Opts(tool)}]} { set Opts(tool) unknown } if {[lindex $caption 1] == "EDITING"} { set subcaption2 [lindex $caption 2] } else { # set subcaption2 [join [lrange $caption 1 end]] set subcaption2 $caption } ${framename}.titlebar.caption configure -text \ "Loaded: ${subcaption1} Editing: ${subcaption2} Tool: $Opts(tool) \ Technology: ${techname}" } } # Allow captioning in the title window by tagging the "load" and "edit" commands # Note that the "box" tag doesn't apply to mouse-button events, so this function # is duplicated by Tk binding of mouse events in the layout window. magic::tag load "[magic::tag load]; magic::captions" magic::tag edit "magic::captions" magic::tag save "magic::captions" magic::tag down "magic::captions" magic::tag box "magic::boxview %W %1" magic::tag move "magic::boxview %W" magic::tag scroll "magic::scrollupdate %W" magic::tag view "magic::scrollupdate %W" magic::tag zoom "magic::scrollupdate %W" magic::tag findbox "magic::scrollupdate %W" magic::tag see "magic::toolupdate %W %1 %2" magic::tag tech "magic::techrebuild %W %1; magic::captions %1" magic::tag drc "magic::drcupdate %1" magic::tag path "[magic::tag path]; magic::techmanager update" magic::tag cellname "magic::mgrupdate %W %1" magic::tag cif "magic::mgrupdate %W %1" magic::tag gds "magic::mgrupdate %W %1" # This should be a list. . . do be done later set lwindow 0 set owindow 0 set Opts(techmgr) 0 set Opts(target) default set Opts(netlist) 0 set Opts(colormap) 0 set Opts(wind3d) 0 set Opts(crosshair) 0 set Opts(hidelocked) 0 set Opts(hidespecial) 0 set Opts(toolbar) 0 set Opts(toolscale) 1.0 set Opts(drc) 1 set Opts(autobuttontext) 1 # Update cell and tech managers in response to a cif or gds read command proc magic::mgrupdate {win {cmdstr ""}} { if {${cmdstr} == "read"} { catch {magic::cellmanager} magic::captions magic::techmanager update } elseif {${cmdstr} == "delete" || ${cmdstr} == "rename"} { catch {magic::cellmanager} magic::captions } elseif {${cmdstr} == "writeable"} { magic::captions } } # Set default width and height to be 3/4 of the screen size. set Opts(geometry) \ "[expr {3 * [winfo screenwidth .] / 4}]x[expr {3 * [winfo screenheight .] \ / 4}]+100+100" # Procedures for the layout scrollbars, which are made from canvas # objects to avoid the problems associated with Tk's stupid scrollbar # implementation. # Repainting function for scrollbars, title, etc., to match the magic # Change the colormap (most useful in 8-bit PseudoColor) proc magic::repaintwrapper { win } { set bgcolor [magic::magiccolor -] ${win}.xscroll configure -background $bgcolor ${win}.xscroll configure -highlightbackground $bgcolor ${win}.xscroll configure -highlightcolor [magic::magiccolor K] ${win}.yscroll configure -background $bgcolor ${win}.yscroll configure -highlightbackground $bgcolor ${win}.yscroll configure -highlightcolor [magic::magiccolor K] ${win}.titlebar.caption configure -background [magic::magiccolor w] ${win}.titlebar.caption configure -foreground [magic::magiccolor c] ${win}.titlebar.message configure -background [magic::magiccolor w] ${win}.titlebar.message configure -foreground [magic::magiccolor c] ${win}.titlebar.pos configure -background [magic::magiccolor w] ${win}.titlebar.pos configure -foreground [magic::magiccolor c] } # Coordinate display callback function # Because "box" calls "box", use the "info level" command to avoid # infinite recursion. proc magic::boxview {win {cmdstr ""}} { if {${cmdstr} == "exists" || ${cmdstr} == "help" || ${cmdstr} == ""} { # do nothing. . . informational only, no change to the box } elseif {${cmdstr} == "remove"} { set framename [winfo parent $win] if {$framename == "."} {return} ${framename}.titlebar.pos configure -text "no box" } elseif {[info level] <= 1} { # For NULL window, find all layout windows and apply update to each. if {$win == {}} { set winlist [magic::windownames layout] foreach lwin $winlist { magic::boxview $lwin } return } set framename [winfo parent $win] if {$framename == "."} {return} if {[catch {set cr [cif scale out]}]} {return} set bval [${win} box values] set bllx [expr {[lindex $bval 0] * $cr }] set blly [expr {[lindex $bval 1] * $cr }] set burx [expr {[lindex $bval 2] * $cr }] set bury [expr {[lindex $bval 3] * $cr }] if {[expr {$bllx == int($bllx)}]} {set bllx [expr {int($bllx)}]} if {[expr {$blly == int($blly)}]} {set blly [expr {int($blly)}]} if {[expr {$burx == int($burx)}]} {set burx [expr {int($burx)}]} if {[expr {$bury == int($bury)}]} {set bury [expr {int($bury)}]} set titletext [format "box (%+g %+g) to (%+g %+g) microns" \ $bllx $blly $burx $bury] ${framename}.titlebar.pos configure -text $titletext } } proc magic::cursorview {win} { global Opts if {$win == {}} { return } set framename [winfo parent $win] if {[catch {set cr [*bypass cif scale out]}]} {return} if {$cr == 0} {return} set olst [${win} cursor internal] set olstx [lindex $olst 0] set olsty [lindex $olst 1] if {$Opts(crosshair)} { *bypass crosshair ${olstx}i ${olsty}i } # Use catch, because occasionally this fails on startup if {[catch { set olstx [expr {$olstx * $cr}] set olsty [expr {$olsty * $cr}] }]} {return} if {[${win} box exists]} { set dlst [${win} box position] set dx [expr {$olstx - ([lindex $dlst 0]) * $cr }] set dy [expr {$olsty - ([lindex $dlst 1]) * $cr }] if {[expr {$dx == int($dx)}]} {set dx [expr {int($dx)}]} if {[expr {$dy == int($dy)}]} {set dy [expr {int($dy)}]} set titletext [format "(%+g %+g) %+g %+g microns" $olstx $olsty $dx $dy] ${framename}.titlebar.pos configure -text $titletext } else { set titletext [format "(%+g %+g) microns" $olstx $olsty] ${framename}.titlebar.pos configure -text $titletext } } proc magic::toolupdate {win {yesno "yes"} {layerlist "none"}} { global Winopts if {$win == {}} { set win [magic::windownames] } # Wind3d has a "see" function, so make sure this is not a 3d window if {$win == [magic::windownames wind3d]} { return } set topname [winfo toplevel $win] set framename [winfo parent $win] # Don't do anything if toolbar is not present if { $Winopts(${topname},toolbar) == 0 } { return } if {$layerlist == "none"} { set layerlist $yesno set yesno "yes" } if {$layerlist == "*"} { set layerlist [magic::tech layer "*"] } # Change from comma-separated list to Tcl list set layerlist [string map {, " "} $layerlist] foreach layer $layerlist { switch $layer { none {set canon ""} allSame {set canon ""} "*" {set canon ""} "$" {set canon ""} connect {set canon ""} errors {set canon $layer} subcell {set canon $layer} labels {set canon $layer} default {set canon [magic::tech layer $layer]} } # Layers may not be in the toolbar if "hidelocked" or # "hidespecial" is used, so catch each configure command. if {$canon != ""} { if {$yesno == "yes"} { catch {${framename}.toolbar.b$canon configure -image img_$canon} catch {${framename}.toolbar.p$canon configure -image pale_$canon} } else { catch {${framename}.toolbar.b$canon configure -image img_space} catch {${framename}.toolbar.p$canon configure -image img_space} } } } } # Generate the toolbar images for a technology proc magic::maketoolimages {} { global Opts # Tool size expands with the GUI scale but can also be expanded independently. set tsize [expr {int($Opts(scale) * $Opts(toolscale) * 16)}] # Generate a layer image for "space" that will be used when layers are # invisible. image create layer img_space -name none -width $tsize -height $tsize set all_layers [concat {errors labels subcell} [magic::tech layer "*"]] foreach layername $all_layers { image create layer img_$layername -name $layername -width $tsize -height $tsize image create layer pale_$layername -name $layername \ -disabled true -icon 23 -width $tsize -height $tsize } } # Generate the toolbar for the wrapper proc magic::maketoolbar { framename } { global Opts global Winopts # Don't do anything if in suspend mode set topname [winfo toplevel $framename] if {[info exists Winopts(${topname},suspend)]} { if { $Winopts(${topname},suspend) > 0} { return } } if {$Opts(toolbar) == 0} { magic::maketoolimages set Opts(toolbar) 1 } # Destroy any existing toolbar before starting set alltools [winfo children ${framename}.toolbar] foreach i $alltools { destroy $i } # All toolbar commands will be passed to the appropriate window set win ${framename}.magic # Generate layer images and buttons for toolbar if {$Opts(hidespecial) == 0} { set special_layers {errors labels subcell} } else { set special_layers {} } if {$Opts(hidelocked) == 0} { set all_layers [concat $special_layers [magic::tech layer "*"]] } else { set all_layers [concat $special_layers [magic::tech unlocked]] } foreach layername $all_layers { button ${framename}.toolbar.b$layername -image img_$layername -command \ "$win see $layername" # Bindings: Entering the button puts the canonical layer name in the # message window. bind ${framename}.toolbar.b$layername \ [subst {focus %W ; ${framename}.titlebar.message configure \ -text "$layername"}] bind ${framename}.toolbar.b$layername \ [subst {${framename}.titlebar.message configure -text ""}] # 3rd mouse button makes layer invisible; 1st mouse button restores it. # 2nd mouse button paints the layer color. Key "p" also does paint, esp. # for users with 2-button mice. Key "e" erases, as does Shift-Button-2. bind ${framename}.toolbar.b$layername \ "$win paint $layername" bind ${framename}.toolbar.b$layername \ "$win paint $layername" bind ${framename}.toolbar.b$layername \ "$win erase $layername" bind ${framename}.toolbar.b$layername \ "$win erase $layername" bind ${framename}.toolbar.b$layername \ "$win see no $layername" bind ${framename}.toolbar.b$layername \ "$win select more area $layername" bind ${framename}.toolbar.b$layername \ "$win select less area $layername" } # Create an additional set of layers and buttons in the "disabled" style # These buttons can be swapped in place of the regular buttons when the # layer is locked. They define no bindings except "u" for "unlock", # and the button bindings (see, see no) foreach layername $all_layers { button ${framename}.toolbar.p$layername -image pale_$layername -command \ "$win see $layername" bind ${framename}.toolbar.p$layername \ "$win see no $layername" bind ${framename}.toolbar.p$layername \ [subst {focus %W ; ${framename}.titlebar.message configure \ -text "$layername (locked)"}] bind ${framename}.toolbar.p$layername \ [subst {${framename}.titlebar.message configure -text ""}] } # Figure out how many columns we need to fit all the layer buttons inside # the toolbar without going outside the window area. set locklist [tech locked] set ncols 0 while {1} { incr ncols set i 0 set j 0 foreach layername $all_layers { if {[lsearch $locklist $layername] >= 0} { grid ${framename}.toolbar.p$layername -row $i -column $j -sticky news } else { grid ${framename}.toolbar.b$layername -row $i -column $j -sticky news } bind ${framename}.toolbar.p$layername \ "$win tech unlock $layername ; \ grid forget ${framename}.toolbar.p$layername ; \ grid ${framename}.toolbar.b$layername \ -row $i -column $j -sticky news" bind ${framename}.toolbar.b$layername \ "$win tech lock $layername ; \ grid forget ${framename}.toolbar.b$layername ; \ grid ${framename}.toolbar.p$layername \ -row $i -column $j -sticky news" incr j if {$j == $ncols} { set j 0 incr i } } # Make sure that window has been created so we will get the correct # height value. update idletasks set winheight [expr {[winfo height ${framename}] - \ [winfo height ${framename}.titlebar]}] set toolheight [lindex [grid bbox ${framename}.toolbar] 3] if {$toolheight <= $winheight} {break} } } # Delete and rebuild the toolbar buttons in response to a "tech load" # command. proc magic::techrebuild {winpath {cmdstr ""}} { global Opts # For NULL window, find all layout windows and apply update to each. if {$winpath == {}} { set winlist [magic::windownames layout] foreach lwin $winlist { magic::techrebuild $lwin $cmdstr } return } set framename [winfo parent $winpath] if {${cmdstr} == "load"} { set Opts(toolbar) 0 maketoolbar ${framename} magic::techmanager init } elseif {${cmdstr} == "lock" || ${cmdstr} == "unlock" || ${cmdstr} == "revert"} { maketoolbar ${framename} } } # Scrollbar callback procs # Procedure to return the effective X and Y scrollbar bounds for the # current view in magic (in pixels) proc magic::setscrollvalues {win} { global Opts set svalues [${win} view get] set bvalues [${win} view bbox] set framename [winfo parent ${win}] if {$framename == "."} {return} set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}] set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}] set wwidth [winfo width ${framename}.xscroll.bar] ;# horizontal scrollbar set wheight [winfo height ${framename}.yscroll.bar] ;# vertical scrollbar # Note that adding 0.0 here forces floating-point set xscale [expr {(0.0 + $wwidth) / $bwidth}] set yscale [expr {(0.0 + $wheight) / $bheight}] set xa [expr {$xscale * ([lindex $svalues 0] - [lindex $bvalues 0]) }] set xb [expr {$xscale * ([lindex $svalues 2] - [lindex $bvalues 0]) }] set ya [expr {$yscale * ([lindex $svalues 1] - [lindex $bvalues 1]) }] set yb [expr {$yscale * ([lindex $svalues 3] - [lindex $bvalues 1]) }] # Magic's Y axis is inverted with respect to X11 window coordinates set ya [expr { $wheight - $ya }] set yb [expr { $wheight - $yb }] set swidth [expr {int($Opts(scale) * 13)}] set slength [expr {$swidth + 2}] ${framename}.xscroll.bar coords slider $xa 2 $xb $slength ${framename}.yscroll.bar coords slider 2 $ya $slength $yb set xb [expr { 1 + ($xa + $xb) / 2 }] set xa [expr { $xb - 2 }] ${framename}.xscroll.bar coords centre $xa 4 $xb $swidth set yb [expr { 1 + ($ya + $yb) / 2 }] set ya [expr { $yb - 2 }] ${framename}.yscroll.bar coords centre 4 $ya $swidth $yb } # Procedure to update scrollbars in response to an internal command # "view" calls "view", so avoid infinite recursion. proc magic::scrollupdate {win} { if {[info level] <= 1} { # For NULL window, find current window if {$win == {}} { set win [magic::windownames] } # Make sure we're not a 3D window, which doesn't take window commands # This is only necessary because the 3D window declares a "view" # command, too. if {$win != [magic::windownames wind3d]} { magic::setscrollvalues $win } } } # scrollview: update the magic display to match the # scrollbar positions. proc magic::scrollview { w win orient } { global scale set v1 $scale($orient,origin) set v2 $scale($orient,update) set delta [expr {$v2 - $v1}] set bvalues [${win} view bbox] set wvalues [${win} windowpositions] # Note that adding 0.000 in expression forces floating-point if {"$orient" == "x"} { set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}] set wwidth [expr {0.000 + [lindex $wvalues 2] - [lindex $wvalues 0]}] set xscale [expr {$bwidth / $wwidth}] ${win} scroll e [expr {$delta * $xscale}]i } else { set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}] set wheight [expr {0.000 + [lindex $wvalues 3] - [lindex $wvalues 1]}] set yscale [expr {$bheight / $wheight}] ${win} scroll s [expr {$delta * $yscale}]i } } # setscroll: get the current cursor position and save it as a # reference point. proc magic::setscroll { w v orient } { global scale set scale($orient,origin) $v set scale($orient,update) $v } proc magic::dragscroll { w v orient } { global scale set v1 $scale($orient,update) set scale($orient,update) $v set delta [expr {$v - $v1}] if { "$orient" == "x" } { $w move slider $delta 0 $w move centre $delta 0 } else { $w move slider 0 $delta $w move centre 0 $delta } } # Scrollbar generator for the wrapper window proc magic::makescrollbar { fname orient win } { global scale global Glyph global Opts set swidth [expr {int($Opts(scale) * 13)}] set scale($orient,update) 0 set scale($orient,origin) 0 # To be done: add glyphs for the arrows if { "$orient" == "x" } { canvas ${fname}.bar -height $swidth -relief sunken -borderwidth 1 button ${fname}.lb -image Glyph(left) -borderwidth 1 \ -command "${win} scroll left .1 w" button ${fname}.ub -image Glyph(right) -borderwidth 1 \ -command "${win} scroll right .1 w" pack ${fname}.lb -side left pack ${fname}.bar -fill $orient -expand true -side left pack ${fname}.ub -side right } else { canvas ${fname}.bar -width $swidth -relief sunken -borderwidth 1 button ${fname}.lb -image Glyph(down) -borderwidth 1 \ -command "${win} scroll down .1 w" button ${fname}.ub -image Glyph(up) -borderwidth 1 \ -command "${win} scroll up .1 w" pack ${fname}.ub pack ${fname}.bar -fill $orient -expand true pack ${fname}.lb } # Create the bar which controls the scrolling and bind actions to it ${fname}.bar create rect 2 2 15 15 -fill steelblue -width 0 -tag slider ${fname}.bar bind slider "magic::setscroll %W %$orient $orient" ${fname}.bar bind slider "magic::scrollview %W $win $orient" ${fname}.bar bind slider "magic::dragscroll %W %$orient $orient" # Create a small mark in the center of the scrolling rectangle which aids # in determining how much the window is being scrolled when the full # scrollbar extends past the window edges. ${fname}.bar create rect 4 4 $swidth $swidth -fill black -width 0 -tag centre ${fname}.bar bind centre "magic::setscroll %W %$orient $orient" ${fname}.bar bind centre "magic::scrollview %W $win $orient" ${fname}.bar bind centre "magic::dragscroll %W %$orient $orient" } # Save all and quit. If something bad happens like an attempt to # write cells into an unwriteable directory, then "cellname list modified" # will contain a list of cells, so prompt to quit with the option to cancel. # If there are no remaining modified and unsaved cells, then just exit. # Because cell "(UNNAMED)" is not written by "writeall force", if that is # the only modified cell, then prompt to change its name and save; then quit. proc magic::saveallandquit {} { magic::promptsave force set modlist [magic::cellname list modified] if {$modlist == {}} { magic::quit -noprompt } else { magic::quit } } # Create the wrapper and open up a layout window in it. proc magic::openwrapper {{cell ""} {framename ""}} { global lwindow global owindow global tk_version global Glyph global Opts global Winopts # Disallow scrollbars and title caption on windows---we'll do these ourselves if {$lwindow == 0} { windowcaption off windowscrollbars off windowborder off } if {$framename == ""} { incr lwindow set framename .layout${lwindow} } set winname ${framename}.pane.top.magic toplevel $framename tkwait visibility $framename # Get scale from the TkDefaultFont size, unless Opts(scale) is already # set. On standard displays, an "M" in the Sans font is usually 10 # pixels wide, and 22 on high resolution displays, so this maps to # a scale of 1 on standard displays and a scale of 2 on high resolution # displays. Make sure scale doesn't go to zero or bad things happen. if [catch {set Opts(scale)}] { set Opts(scale) [expr {max(1, int([font measure TkDefaultFont M] / 10))}] } # Resize the window if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} { catch {wm geometry ${framename} $Opts(geometry)} } # Create a paned window top--bottom inside the top level window to accomodate # a resizable command entry window at the bottom. Sashwidth is zero by default # but is resized by enabling the command entry window. panedwindow ${framename}.pane -orient vertical -sashrelief groove -sashwidth 6 frame ${framename}.pane.top frame ${framename}.pane.bot set layoutframe ${framename}.pane.top ${framename}.pane add ${framename}.pane.top ${framename}.pane add ${framename}.pane.bot ${framename}.pane paneconfigure ${framename}.pane.top -stretch always ${framename}.pane paneconfigure ${framename}.pane.bot -hide true pack ${framename}.pane -side top -fill both -expand true set swidth [expr {int($Opts(scale) * 13)}] frame ${layoutframe}.xscroll -height $swidth frame ${layoutframe}.yscroll -width $swidth magic::makeglyphimages magic::makescrollbar ${layoutframe}.xscroll x ${winname} magic::makescrollbar ${layoutframe}.yscroll y ${winname} button ${layoutframe}.zb -image Glyph(zoom) -borderwidth 1 -command "${winname} zoom 2" # Add bindings for mouse buttons 2 and 3 to the zoom button bind ${layoutframe}.zb "${winname} zoom 0.5" bind ${layoutframe}.zb "${winname} view" frame ${layoutframe}.titlebar label ${layoutframe}.titlebar.caption -text "Loaded: none Editing: none Tool: box" \ -foreground white -background sienna4 -anchor w -padx 15 label ${layoutframe}.titlebar.message -text "" -foreground white \ -background sienna4 -anchor w -padx 5 label ${layoutframe}.titlebar.pos -text "" -foreground white \ -background sienna4 -anchor w -padx 5 # Menu buttons frame ${layoutframe}.titlebar.mbuttons # File menubutton ${layoutframe}.titlebar.mbuttons.file -text File -relief raised \ -menu ${layoutframe}.titlebar.mbuttons.file.toolmenu -borderwidth 2 # Edit menubutton ${layoutframe}.titlebar.mbuttons.edit -text Edit -relief raised \ -menu ${layoutframe}.titlebar.mbuttons.edit.toolmenu -borderwidth 2 # Cell menubutton ${layoutframe}.titlebar.mbuttons.cell -text Cell -relief raised \ -menu ${layoutframe}.titlebar.mbuttons.cell.toolmenu -borderwidth 2 # Window menubutton ${layoutframe}.titlebar.mbuttons.win -text Window -relief raised \ -menu ${layoutframe}.titlebar.mbuttons.win.toolmenu -borderwidth 2 # Layers menubutton ${layoutframe}.titlebar.mbuttons.layers -text Layers -relief raised \ -menu ${layoutframe}.titlebar.mbuttons.layers.toolmenu -borderwidth 2 # DRC menubutton ${layoutframe}.titlebar.mbuttons.drc -text Drc -relief raised \ -menu ${layoutframe}.titlebar.mbuttons.drc.toolmenu -borderwidth 2 # Netlist # menubutton ${layoutframe}.titlebar.mbuttons.netlist -text Neltist -relief raised \ # -menu ${layoutframe}.titlebar.mbuttons.netlist.netlistmenu -borderwidth 2 # Help # menubutton ${layoutframe}.titlebar.mbuttons.help -text Help -relief raised \ # -menu ${layoutframe}.titlebar.mbuttons.help.helpmenu -borderwidth 2 # Options menubutton ${layoutframe}.titlebar.mbuttons.opts -text Options -relief raised \ -menu ${layoutframe}.titlebar.mbuttons.opts.toolmenu -borderwidth 2 pack ${layoutframe}.titlebar.mbuttons.file -side left pack ${layoutframe}.titlebar.mbuttons.edit -side left pack ${layoutframe}.titlebar.mbuttons.cell -side left pack ${layoutframe}.titlebar.mbuttons.win -side left pack ${layoutframe}.titlebar.mbuttons.layers -side left pack ${layoutframe}.titlebar.mbuttons.drc -side left # pack ${layoutframe}.titlebar.mbuttons.netlist -side left # pack ${layoutframe}.titlebar.mbuttons.help -side left pack ${layoutframe}.titlebar.mbuttons.opts -side left # DRC status button checkbutton ${layoutframe}.titlebar.drcbutton -text "DRC" -anchor w \ -borderwidth 2 -variable Opts(drc) \ -foreground white -background sienna4 -selectcolor green \ -command [subst { if { \$Opts(drc) } { drc on } else { drc off } }] magic::openwindow $cell $winname # Create toolbar frame. Make sure it has the same visual and depth as # the layout window, so there will be no problem using the GCs from the # layout window to paint into the toolbar. frame ${layoutframe}.toolbar \ -visual "[winfo visual ${winname}] [winfo depth ${winname}]" # Repaint to magic colors magic::repaintwrapper ${layoutframe} grid ${layoutframe}.titlebar -row 0 -column 0 -columnspan 3 -sticky news grid ${layoutframe}.yscroll -row 1 -column 0 -sticky ns grid $winname -row 1 -column 1 -sticky news grid ${layoutframe}.zb -row 2 -column 0 grid ${layoutframe}.xscroll -row 2 -column 1 -sticky ew # The toolbar is not attached by default grid rowconfigure ${layoutframe} 1 -weight 1 grid columnconfigure ${layoutframe} 1 -weight 1 grid ${layoutframe}.titlebar.mbuttons -row 0 -column 0 -sticky news grid ${layoutframe}.titlebar.drcbutton -row 0 -column 1 -sticky news grid ${layoutframe}.titlebar.caption -row 0 -column 2 -sticky news grid ${layoutframe}.titlebar.message -row 0 -column 3 -sticky news grid ${layoutframe}.titlebar.pos -row 0 -column 4 -sticky news grid columnconfigure ${layoutframe}.titlebar 2 -weight 1 bind $winname "focus %W ; set Opts(focus) $framename" # Note: Tk binding bypasses the event proc, so it is important to # set the current point; otherwise, the cursor will report the # wrong position and/or the wrong window. HOWEVER we should wrap # this command with the "bypass" command such that it does not # reset any current input redirection to the terminal. bind ${winname} "*bypass setpoint %x %y ${winname}; \ magic::cursorview ${winname}" set Winopts(${framename},toolbar) 1 set Winopts(${framename},cmdentry) 0 # ################################# # File # ################################# set m [menu ${layoutframe}.titlebar.mbuttons.file.toolmenu -tearoff 0] $m add command -label "Open..." -command {magic::promptload magic} # $m add command -label "Save" -command {magic::save } $m add command -label "Save..." -command {magic::promptsave magic} # $m add command -label "Save as..." -command {echo "not implemented"} # $m add command -label "Save selection..." -command {echo "not implemented"} $m add separator $m add command -label "Flush changes" -command {magic::flush} $m add separator # $m add command -label "Read CIF" -command {magic::promptload cif} $m add command -label "Read GDS" -command {magic::promptload gds} # $m add separator # $m add command -label "Write CIF" -command {magic::promptsave cif} $m add command -label "Write GDS" -command {magic::promptsave gds} # $m add separator # $m add command -label "Print..." -command {echo "not implemented"} $m add separator $m add command -label "Save All and Quit" -command {magic::saveallandquit} $m add command -label "Quit" -command {magic::quit} # ################################# # Edit # ################################# set m [menu ${layoutframe}.titlebar.mbuttons.edit.toolmenu -tearoff 0] # $m add command -label "Cut" -command {echo "not implemented"} # $m add command -label "Copy" -command {echo "not implemented"} # $m add command -label "Paste" -command {echo "not implemented"} $m add command -label "Delete" -command {delete} $m add separator $m add command -label "Select Area" -command {select area} $m add command -label "Select Clear" -command {select clear} $m add separator $m add command -label "Undo" -command {magic::undo} $m add command -label "Redo" -command {magic::redo} # $m add command -label "Repeat Last" -command {echo "not implemented"} $m add separator $m add command -label "Rotate 90 degree" -command {magic::clock} $m add command -label "Mirror Up/Down" -command {magic::upsidedown} $m add command -label "Mirror Left/Right" -command {magic::sideways} $m add separator $m add command -label "Move Right" -command {move right 1} $m add command -label "Move Left" -command {move left 1} $m add command -label "Move Up" -command {move up 1} $m add command -label "Move Down" -command {move down 1} $m add separator $m add command -label "Stretch Right" -command {stretch right 1} $m add command -label "Stretch Left" -command {stretch left 1} $m add command -label "Stretch Up" -command {stretch up 1} $m add command -label "Stretch Down" -command {stretch down 1} $m add separator $m add command -label "Text ..." \ -command [subst {magic::update_texthelper; \ wm deiconify .texthelper ; raise .texthelper}] # ################################# # Cell # ################################# set m [menu ${layoutframe}.titlebar.mbuttons.cell.toolmenu -tearoff 0] $m add command -label "New..." -command {magic::prompt_dialog new} $m add command -label "Save as..." -command {magic::prompt_dialog save} $m add command -label "Select" -command {magic::select cell} $m add command -label "Place Instance" -command {magic::promptload getcell} # $m add command -label "Rename" -command {echo "not implemented"} $m add separator $m add command -label "Down hierarchy" -command {magic::pushstack} $m add command -label "Up hierarchy" -command {magic::popstack} $m add separator $m add command -label "Edit" -command {magic::edit} $m add separator $m add command -label "Delete" -command \ {magic::cellname delete [magic::cellname list window]} $m add separator $m add command -label "Expand Toggle" -command {magic::expand toggle} $m add command -label "Expand" -command {magic::expand} $m add command -label "Unexpand" -command {magic::unexpand} $m add separator $m add command -label "Lock Cell" -command {magic::instance lock} $m add command -label "Unlock Cell" -command {magic::instance unlock} # ################################# # Window # ################################# set m [menu ${layoutframe}.titlebar.mbuttons.win.toolmenu -tearoff 0] $m add command -label "Clone" -command \ {magic::openwrapper [magic::cellname list window]} $m add command -label "New" -command "magic::openwrapper" $m add command -label "Set Editable" -command \ "pushbox ; select top cell ; edit ; popbox" $m add command -label "Close" -command "closewrapper ${framename}" $m add separator $m add command -label "Full View" -command {magic::view} $m add command -label "Redraw" -command {magic::redraw} $m add command -label "Zoom Out" -command {magic::zoom 2} $m add command -label "Zoom In" -command {magic::zoom 0.5} $m add command -label "Zoom Box" -command {magic::findbox zoom} $m add separator $m add command -label "Grid on" -command {magic::grid on} $m add command -label "Grid off" -command {magic::grid off} $m add command -label "Snap-to-grid on" -command {magic::snap on} $m add command -label "Snap-to-grid off" -command {magic::snap off} $m add command -label "Measure box" -command {magic::box } $m add separator $m add command -label "Set grid 0.05um" -command {magic::grid 0.05um} $m add command -label "Set grid 0.10um" -command {magic::grid 0.10um} $m add command -label "Set grid 0.50um" -command {magic::grid 0.50um} $m add command -label "Set grid 1.00um" -command {magic::grid 1.00um} $m add command -label "Set grid 5.00um" -command {magic::grid 5.00um} $m add command -label "Set grid 10.0um" -command {magic::grid 10.0um} # $m add command -label "Set grid ..." -command {echo "not implemented"} # ################################# # Layers # ################################# set m [menu ${layoutframe}.titlebar.mbuttons.layers.toolmenu -tearoff 0] $m add command -label "Protect Base Layers" -command {magic::tech revert} $m add command -label "Unlock Base Layers" -command {magic::tech unlock *} $m add separator $m add command -label "Clear Feedback" -command {magic::feedback clear} $m add separator # ################################# # DRC # ################################# set m [menu ${layoutframe}.titlebar.mbuttons.drc.toolmenu -tearoff 0] # $m add command -label "DRC On" -command {drc on} # $m add command -label "DRC Off" -command {drc off} # $m add separator $m add command -label "DRC update" -command {drc check; drc why} $m add command -label "DRC report" -command {drc why} $m add command -label "DRC Find next error" -command {drc find; findbox zoom} $m add separator $m add command -label "DRC Fast" -command {drc style drc(fast)} $m add command -label "DRC Complete" -command {drc style drc(full)} set m [menu ${layoutframe}.titlebar.mbuttons.opts.toolmenu -tearoff 0] $m add check -label "Toolbar" -variable Winopts(${framename},toolbar) \ -command [subst {if { \$Winopts(${framename},toolbar) } { \ magic::maketoolbar ${layoutframe} ; \ grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new ; \ } else { \ grid forget ${layoutframe}.toolbar } }] $m add check -label "Toolbar Hide Locked" \ -variable Opts(hidelocked) \ -command "magic::maketoolbar ${layoutframe}" .winmenu add radio -label ${framename} -variable Opts(target) -value ${winname} if {$tk_version >= 8.5} { $m add check -label "Cell Manager" -variable Opts(cellmgr) \ -command [subst { magic::cellmanager create; \ if { \$Opts(cellmgr) } { \ wm deiconify .cellmgr ; raise .cellmgr \ } else { \ wm withdraw .cellmgr } }] .winmenu entryconfigure last -command ".cellmgr.target.list configure \ -text ${framename}" } if {$tk_version >= 8.5} { $m add check -label "Library Manager" -variable Opts(libmgr) \ -command [subst { magic::libmanager create; \ if { \$Opts(libmgr) } { \ wm deiconify .libmgr ; raise .libmgr \ } else { \ wm withdraw .libmgr } }] .winmenu entryconfigure last -command ".libmgr.target.list configure \ -text ${framename}" } $m add check -label "Tech Manager" -variable Opts(techmgr) \ -command [subst { magic::techmanager create; \ if { \$Opts(techmgr) } { \ wm deiconify .techmgr ; raise .techmgr \ } else { \ wm withdraw .techmgr } }] $m add check -label "DRC Manager" -variable Opts(drcmgr) \ -command [subst { magic::drcmanager create; \ if { \$Opts(drcmgr) } { \ wm deiconify .drcmgr ; raise .drcmgr \ } else { \ wm withdraw .drcmgr } }] $m add check -label "Netlist Window" -variable Opts(netlist) \ -command [subst { if { \[windownames netlist\] != {}} { \ set Opts(netlist) 0 ; closewindow \[windownames netlist\] \ } else { \ set Opts(netlist) 1 ; specialopen netlist \ } }] $m add check -label "Colormap Window" -variable Opts(colormap) \ -command [subst { if { \[windownames color\] != {}} { \ set Opts(colormap) 0 ; closewindow \[windownames color\] \ } else { \ set Opts(colormap) 1 ; specialopen color \ } }] $m add check -label "3D Display" -variable Opts(wind3d) \ -command [subst { if { \[windownames wind3d\] != {}} { \ set Opts(wind3d) 0 ; .render.magic closewindow ; \ destroy .render \ } else { \ set Opts(wind3d) 1 ; \ magic::render3d \[${winname} cellname list window\] \ } }] $m add check -label "Window Command Entry" \ -variable Winopts(${framename},cmdentry) \ -command [subst { if { \$Winopts(${framename},cmdentry) } { \ addcommandentry $framename \ } else { \ deletecommandentry $framename } }] $m add check -label "Crosshair" \ -variable Opts(crosshair) \ -command {if {$Opts(crosshair) == 0} {crosshair off}} catch {addmazehelper $m} # Set the default view update idletasks ${winname} magic::view magic::captions # If the toolbar is turned on, invoke the toolbar button if { $Winopts(${framename},toolbar) == 1} { magic::maketoolbar ${layoutframe} grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new } # Remove "open" and "close" macros so they don't generate non-GUI # windows or (worse) blow away the window inside the GUI frame if {[magic::macro list o] == "openwindow"} { magic::macro o \ "incr owindow ;\ set rpt \[cursor screen\] ;\ set rptx \[lindex \$rpt 0\] ;\ set rpty \[lindex \$rpt 1\] ;\ set Winopts(.owindow\$owindow,geometry) 500x500+\$rptx+\$rpty ;\ openwrapper \[\$Opts(focus)*.magic cellname list window\] \ .owindow\$owindow ;\ .owindow\$owindow*.magic view \[box values\]" } if {[magic::macro list O] == "closewindow"} { magic::macro O "closewrapper \$Opts(focus)" } # Make sure that closing from the window manager is equivalent to # the command "closewrapper" wm protocol ${framename} WM_DELETE_WINDOW "closewrapper ${framename}" # If the variable $Opts(callback) is defined, then attempt to execute it. catch {eval $Opts(callback)} # If the variable $Winopts(callback) is defined, then attempt to execute it. catch {eval $Winopts(${framename}, callback)} # Since one purpose of the window callback is to customize the menus, # run the automatic generation of accelerator key text at the end. # This can be subverted by setting Opts(autobuttontext) to 0, e.g., # to put it at the top of the Winopts callback and then generate # override values for specific buttons. if {$Opts(autobuttontext)} { catch {magic::button_auto_bind_text $layoutframe} } return ${winname} } # Delete the wrapper and the layout window in it. proc magic::closewrapper { framename } { global tk_version global Opts # Remove this window from the target list in .winmenu # (used by, e.g., cellmanager) set layoutframe ${framename}.pane.top if { $Opts(target) == "${layoutframe}.magic" } { set Opts(target) "default" if {$tk_version >= 8.5} { if {![catch {wm state .cellmgr}]} { .cellmgr.target.list configure -text "default" } } } set idx [.winmenu index $framename] .winmenu delete $idx ${layoutframe}.magic magic::closewindow destroy $framename } # This procedure adds a command-line entry window to the bottom of # a wrapper window (rudimentary functionality---incomplete) proc magic::addcommandentry { framename } { set commandframe ${framename}.pane.bot if {![winfo exists ${commandframe}.eval]} { tkshell::YScrolled_Text ${commandframe}.eval -height 5 tkshell::MakeEvaluator ${commandframe}.eval.text \ "${framename}>" ${framename}.pane.top.magic pack ${commandframe}.eval -side top -fill both -expand true ${framename}.pane paneconfigure ${framename}.pane.bot -stretch never ${framename}.pane paneconfigure ${framename}.pane.bot -minsize 50 } set entercmd [bind ${framename}.pane.top.magic ] set bindstr "$entercmd ; macro XK_colon \"set Opts(redirect) 1;\ focus ${commandframe}.eval.text\";\ alias puts tkshell::PutsTkShell" bind ${commandframe}.eval \ "focus ${commandframe}.eval.text ; set Opts(focus) $framename ;\ catch {unset Opts(redirect)}" bind ${framename}.pane.top.magic $bindstr # Make command entry window visible ${framename}.pane paneconfigure ${framename}.pane.bot -hide false } # Remove the command entry window from the bottom of a frame. proc magic::deletecommandentry { framename } { set commandframe ${framename}.pane.bot ::grid forget ${commandframe}.eval # Remove the last bindings for set bindstr [bind ${framename}.pane.top.magic ] set i [string first "; macro" $bindstr] set bindstr [string range $bindstr 0 $i-1] bind ${framename}.pane.top.magic $bindstr # Restore the keybinding for colon imacro XK_colon ":" # Restore the alias for "puts" alias puts ::tkcon_puts # Make command entry window invisible ${framename}.pane paneconfigure ${framename}.pane.bot -hide true } namespace import magic::openwrapper puts "Use openwrapper to create a new GUI-based layout window" namespace import magic::closewrapper puts "Use closewrapper to remove a new GUI-based layout window" # Create a simple wrapper for the 3D window. . . this can be # greatly expanded upon. proc magic::render3d {{cell ""}} { global Opts toplevel .render tkwait visibility .render magic::specialopen wind3d $cell .render.magic .render.magic cutbox box set Opts(cutbox) 1 wm protocol .render WM_DELETE_WINDOW "set Opts(wind3d) 0 ; \ .render.magic closewindow ; destroy .render" frame .render.title pack .render.title -expand true -fill x -side top checkbutton .render.title.cutbox -text "Cutbox" -variable Opts(cutbox) \ -foreground white -background sienna4 -anchor w -padx 15 \ -command [subst { if { \$Opts(cutbox) } { .render.magic cutbox box \ } else { \ .render.magic cutbox none } }] if {$cell == ""} {set cell default} label .render.title.msg -text "3D Rendering window Cell: $cell" \ -foreground white -background sienna4 -anchor w -padx 15 pack .render.title.cutbox -side left pack .render.title.msg -side right -fill x -expand true pack .render.magic -expand true -fill both -side bottom bind .render.magic {focus %W} }