#----------------------------------------------------- # Magic/TCL general-purpose toolkit procedures #----------------------------------------------------- # Tim Edwards # February 11, 2007 # Revision 0 # December 15, 2016 # Revision 1 #-------------------------------------------------------------- # Sets up the environment for a toolkit. The toolkit must # supply a namespace that is the "library name". For each # parameter-defined device ("gencell") type, the toolkit must # supply five procedures: # # 1. ${library}::${gencell_type}_defaults {} # 2. ${library}::${gencell_type}_convert {parameters} # 3. ${library}::${gencell_type}_dialog {parameters} # 4. ${library}::${gencell_type}_check {parameters} # 5. ${library}::${gencell_type}_draw {parameters} # # The first defines the parameters used by the gencell, and # declares default parameters to use when first generating # the window that prompts for the device parameters prior to # creating the device. The second converts between parameters # in a SPICE netlist and parameters used by the dialog, # performing units conversion and parameter name conversion as # needed. The third builds the dialog window for entering # device parameters. The fourth checks the parameters for # legal values. The fifth draws the device. # # If "library" is not specified then it defaults to "toolkit". # Otherwise, where specified, the name "gencell_fullname" # is equivalent to "${library}::${gencell_type}" # # Each gencell is defined by cell properties as created by # the "cellname property" command. Specific properties used # by the toolkit are: # # library --- name of library (see above, default "toolkit") # gencell --- base name of gencell (gencell_type, above) # parameters --- list of gencell parameter-value pairs #-------------------------------------------------------------- # Initialize toolkit menus to the wrapper window global Opts #---------------------------------------------------------------- # Add a menu button to the Magic wrapper window for the toolkit #---------------------------------------------------------------- proc magic::add_toolkit_menu {framename button_text {library toolkit}} { menubutton ${framename}.titlebar.mbuttons.${library} \ -text $button_text \ -relief raised \ -menu ${framename}.titlebar.mbuttons.${library}.toolmenu \ -borderwidth 2 menu ${framename}.titlebar.mbuttons.${library}.toolmenu -tearoff 0 pack ${framename}.titlebar.mbuttons.${library} -side left } #----------------------------------------------------------------- # Add a menu item to the toolkit menu calling the default function #----------------------------------------------------------------- proc magic::add_toolkit_button {framename button_text gencell_type \ {library toolkit} args} { set m ${framename}.titlebar.mbuttons.${library}.toolmenu $m add command -label "$button_text" -command \ "magic::gencell $library::$gencell_type {} $args" } #---------------------------------------------------------------- # Add a menu item to the toolkit menu that calls the provided # function #---------------------------------------------------------------- proc magic::add_toolkit_command {framename button_text \ command {library toolkit} args} { set m ${framename}.titlebar.mbuttons.${library}.toolmenu $m add command -label "$button_text" -command "$command $args" } #---------------------------------------------------------------- # Add a separator to the toolkit menu #---------------------------------------------------------------- proc magic::add_toolkit_separator {framename {library toolkit}} { set m ${framename}.titlebar.mbuttons.${library}.toolmenu $m add separator } #----------------------------------------------------- # Add "Ctrl-P" key callback for device selection #----------------------------------------------------- magic::macro ^P "magic::gencell {} ; raise .params" #------------------------------------------------------------- # Add tag callback to select to update the gencell window #------------------------------------------------------------- magic::tag select "[magic::tag select]; magic::gencell_update %1" #------------------------------------------------------------- # gencell # # Main routine to call a cell from either a menu button or # from a script or command line. The name of the device # is required, followed by the name of the instance, followed # by an optional list of parameters. Handling depends on # instname and args: # # gencell_name is either the name of an instance or the name # of the gencell in the form ::. # # name args action #----------------------------------------------------------------- # none empty interactive, new device w/defaults # none specified interactive, new device w/parameters # instname empty interactive, edit device # instname specified non-interactive, change device # device empty non-interactive, new device w/defaults # device specified non-interactive, new device w/parameters # #------------------------------------------------------------- # Also, if instname is empty and gencell_name is not specified, # and if a device is selected in the layout, then gencell # behaves like line 3 above (instname exists, args is empty). # Note that macro Ctrl-P calls gencell this way. If gencell_name # is not specified and nothing is selected, then gencell{} # does nothing. # # "args" must be a list of the cell parameters in key:value pairs, # and an odd number is not legal; the exception is that if the # first argument is "-spice", then the list of parameters is # expected to be in the format used in a SPICE netlist, and the # parameter names and values will be treated accordingly. #------------------------------------------------------------- proc magic::gencell {gencell_name {instname {}} args} { # Pull "-spice" out of args, if it is the first argument if {[lindex $args 0] == "-spice"} { set spicemode 1 set args [lrange $args 1 end] } else { set spicemode 0 } set argpar [dict create {*}$args] if {$gencell_name == {}} { # Find selected item (to-do: handle multiple selections) set wlist [what -list] set clist [lindex $wlist 2] set ccell [lindex $clist 0] set ginst [lindex $ccell 0] set gname [lindex $ccell 1] set library [cellname list property $gname library] if {$library == {}} { set library toolkit } set gencell_type [cellname list property $gname gencell] if {$gencell_type == {}} { if {![regexp {^(.*)_[0-9]*$} $gname valid gencell_type]} { # Error message error "No gencell device is selected!" } } # need to incorporate argpar? set parameters [cellname list property $gname parameters] set parameters [magic::gencell_defaults $gencell_type $library $parameters] magic::gencell_dialog $ginst $gencell_type $library $parameters } else { # Parse out library name from gencell_name, otherwise default # library is assumed to be "toolkit". if {[regexp {^([^:]+)::([^:]+)$} $gencell_name valid library gencell_type] \ == 0} { set library "toolkit" set gencell_type $gencell_name } if {$instname == {}} { # Case: Interactive, new device with parameters in args (if any) if {$spicemode == 1} { # Legal not to have a *_convert routine if {[info commands ${library}::${gencell_type}_convert] != ""} { set argpar [${library}::${gencell_type}_convert $argpar] } } set parameters [magic::gencell_defaults $gencell_type $library $argpar] magic::gencell_dialog {} $gencell_type $library $parameters } else { # Check if instance exists or not in the cell set cellname [instance list celldef $instname] if {$cellname != ""} { # Case: Change existing instance, parameters in args (if any) select cell $instname set devparms [cellname list property $gencell_type parameters] set parameters [magic::gencell_defaults $gencell_type $library $devparms] if {[dict exists $parameters nocell]} { set arcount [array -list count] set arpitch [array -list pitch] dict set parameters nx [lindex $arcount 1] dict set parameters ny [lindex $arcount 3] dict set parameters pitchx $delx dict set parameters pitchy $dely } if {[dict size $argpar] == 0} { # No changes entered on the command line, so start dialog magic::gencell_dialog $instname $gencell_type $library $parameters } else { # Apply specified changes without invoking the dialog if {$spicemode == 1} { set argpar [${library}::${gencell_type}_convert $argpar] } set parameters [dict merge $parameters $argpar] magic::gencell_change $instname $gencell_type $library $parameters } } else { # Case: Non-interactive, create new device with parameters # in args (if any) if {$spicemode == 1} { set argpar [${library}::${gencell_type}_convert $argpar] } set parameters [magic::gencell_defaults $gencell_type $library $argpar] set inst_defaultname [magic::gencell_create \ $gencell_type $library $parameters] select cell $inst_defaultname identify $instname } } } } #------------------------------------------------------------- # gencell_getparams # # Go through the parameter window and collect all of the # named parameters and their values. Return the result as # a dictionary. #------------------------------------------------------------- proc magic::gencell_getparams {} { set parameters [dict create] set slist [grid slaves .params.edits] foreach s $slist { if {[regexp {^.params.edits.(.*)_ent$} $s valid pname] != 0} { set value [subst \$magic::${pname}_val] } elseif {[regexp {^.params.edits.(.*)_chk$} $s valid pname] != 0} { set value [subst \$magic::${pname}_val] } elseif {[regexp {^.params.edits.(.*)_sel$} $s valid pname] != 0} { set value [subst \$magic::${pname}_val] } dict set parameters $pname $value } return $parameters } #------------------------------------------------------------- # gencell_setparams # # Fill in values in the dialog from a set of parameters #------------------------------------------------------------- proc magic::gencell_setparams {parameters} { if {[catch {set state [wm state .params]}]} {return} set slist [grid slaves .params.edits] foreach s $slist { if {[regexp {^.params.edits.(.*)_ent$} $s valid pname] != 0} { set value [dict get $parameters $pname] set magic::${pname}_val $value } elseif {[regexp {^.params.edits.(.*)_chk$} $s valid pname] != 0} { set value [dict get $parameters $pname] set magic::${pname}_val $value } elseif {[regexp {^.params.edits.(.*)_sel$} $s valid pname] != 0} { set value [dict get $parameters $pname] set magic::${pname}_val $value .params.edits.${pname}_sel configure -text $value } elseif {[regexp {^.params.edits.(.*)_txt$} $s valid pname] != 0} { if {[dict exists $parameters $pname]} { set value [dict get $parameters $pname] .params.edits.${pname}_txt configure -text $value } } } } #------------------------------------------------------------- # gencell_change # # Redraw a gencell with new parameters. #------------------------------------------------------------- proc magic::gencell_change {instname gencell_type library parameters} { global Opts suspendall set newinstname $instname if {$parameters == {}} { # Get device defaults set pdefaults [${library}::${gencell_type}_defaults] # Pull user-entered values from dialog set parameters [dict merge $pdefaults [magic::gencell_getparams]] set newinstname [.params.title.ient get] if {$newinstname == "(default)"} {set newinstname $instname} if {$newinstname == $instname} {set newinstname $instname} if {[instance list exists $newinstname] != ""} {set newinstname $instname} } if {[dict exists $parameters gencell]} { # Setting special parameter "gencell" forces the gencell to change type set gencell_type [dict get $parameters gencell] } if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ checkerr]} { puts stderr $checkerr } magic::gencell_setparams $parameters if {[dict exists $parameters gencell]} { set parameters [dict remove $parameters gencell] } set gname [instance list celldef $instname] # Guard against instance having been deleted if {$gname == ""} { resumeall return } set snaptype [snap list] snap internal set savebox [box values] catch {setpoint 0 0 $Opts(focus)} if [dict exists $parameters nocell] { select cell $instname delete if {[catch {set newinst [${library}::${gencell_type}_draw $parameters]} \ drawerr]} { puts stderr $drawerr } select cell $newinst } else { pushstack $gname select cell tech unlock * erase * if {[catch {${library}::${gencell_type}_draw $parameters} drawerr]} { puts stderr $drawerr } property parameters $parameters property gencell ${gencell_type} tech revert popstack select cell $instname } identify $newinstname eval "box values $savebox" snap $snaptype resumeall redraw } #------------------------------------------------------------- # Assign a unique name for a gencell # # Note: This depends on the unlikelihood of the name # existing in a cell on disk. Only cells in memory are # checked for name collisions. Since the names will go # into SPICE netlists, names must be unique when compared # in a case-insensitive manner. Using base-36 (alphabet and # numbers), each gencell name with 6 randomized characters # has a 1 in 4.6E-10 chance of reappearing. #------------------------------------------------------------- proc magic::get_gencell_name {gencell_type} { while {true} { set postfix "" for {set i 0} {$i < 6} {incr i} { set pint [expr 48 + int(rand() * 36)] if {$pint > 57} {set pint [expr $pint + 39]} append postfix [format %c $pint] } if {[cellname list exists ${gencell_type}_$postfix] == 0} {break} } return ${gencell_type}_$postfix } #------------------------------------------------------------- # gencell_create # # Instantiate a new gencell called $gname. If $gname # does not already exist, create it by calling its # drawing routine. # # Don't rely on pushbox/popbox since we don't know what # the drawing routine is going to do to the stack! #------------------------------------------------------------- proc magic::gencell_create {gencell_type library parameters} { global Opts suspendall set newinstname "" # Get device defaults if {$parameters == {}} { # Pull user-entered values from dialog set dialogparams [magic::gencell_getparams] if {[dict exists $dialogparams gencell]} { # Setting special parameter "gencell" forces the gencell to change type set gencell_type [dict get $dialogparams gencell] } set pdefaults [${library}::${gencell_type}_defaults] set parameters [dict merge $pdefaults $dialogparams] set newinstname [.params.title.ient get] if {$newinstname == "(default)"} {set newinstname ""} if {[instance list exists $newinstname] != ""} {set newinstname ""} } else { if {[dict exists $parameters gencell]} { # Setting special parameter "gencell" forces the gencell to change type set gencell_type [dict get $parameters gencell] } set pdefaults [${library}::${gencell_type}_defaults] set parameters [dict merge $pdefaults $parameters] } if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ checkerr]} { puts stderr $checkerr } magic::gencell_setparams $parameters if {[dict exists $parameters gencell]} { set parameters [dict remove $parameters gencell] } set snaptype [snap list] snap internal set savebox [box values] catch {setpoint 0 0 $Opts(focus)} if [dict exists $parameters nocell] { if {[catch {set instname [${library}::${gencell_type}_draw $parameters]} \ drawerr]} { puts stderr $drawerr } set gname [instance list celldef $instname] eval "box values $savebox" } else { set gname [magic::get_gencell_name ${gencell_type}] cellname create $gname pushstack $gname if {[catch {${library}::${gencell_type}_draw $parameters} drawerr]} { puts stderr $drawerr } property library $library property gencell $gencell_type property parameters $parameters popstack eval "box values $savebox" set instname [getcell $gname] expand } if {$newinstname != ""} { identify $newinstname set instname $newinstname } snap $snaptype resumeall redraw return $instname } #----------------------------------------------------- # Add a standard entry parameter to the gencell window #----------------------------------------------------- proc magic::add_entry {pname ptext parameters} { if [dict exists $parameters $pname] { set value [dict get $parameters $pname] } else { set value "" } set numrows [lindex [grid size .params.edits] 1] label .params.edits.${pname}_lab -text $ptext entry .params.edits.${pname}_ent -background white -textvariable magic::${pname}_val grid .params.edits.${pname}_lab -row $numrows -column 0 \ -sticky ens -ipadx 5 -ipady 2 grid .params.edits.${pname}_ent -row $numrows -column 1 \ -sticky ewns -ipadx 5 -ipady 2 .params.edits.${pname}_ent insert end $value set magic::${pname}_val $value } #---------------------------------------------------------- # Default entry callback, without any dependencies. Each # parameter changed #---------------------------------------------------------- proc magic::add_check_callbacks {gencell_type library} { set wlist [winfo children .params.edits] foreach w $wlist { if {[regexp {\.params\.edits\.(.+)_ent} $w valid pname]} { # Add callback on enter or focus out bind $w \ "magic::update_dialog {} $pname $gencell_type $library" bind $w \ "magic::update_dialog {} $pname $gencell_type $library" } } } #---------------------------------------------------------- # Add a dependency between entries. When one updates, the # others will be recomputed according to the callback # function. # # The callback function is passed the value of all # parameters for the device, overridden by the values # in the dialog. The routine computes the dependent # values and writes them back to the parameter dictionary. # The callback function must return the modified parameters # dictionary. # # Also handle dependencies on checkboxes and selection lists #---------------------------------------------------------- proc magic::add_dependency {callback gencell_type library args} { if {[llength $args] == 0} { # If no arguments are given, do for all parameters set parameters ${library}::${gencell_type}_defaults magic::add_dependency $callback $gencell_type $library \ {*}[dict keys $parameters] return } set clist [winfo children .params.edits] foreach pname $args { if {[lsearch $clist .params.edits.${pname}_ent] >= 0} { # Add callback on enter or focus out bind .params.edits.${pname}_ent \ "magic::update_dialog $callback $pname $gencell_type $library" bind .params.edits.${pname}_ent \ "magic::update_dialog $callback $pname $gencell_type $library" } elseif {[lsearch $clist .params.edits.${pname}_chk] >= 0} { # Add callback on checkbox change state .params.edits.${pname}_chk configure -command \ "magic::update_dialog $callback $pname $gencell_type $library" } elseif {[lsearch $clist .params.edits.${pname}_sel] >= 0} { set smenu .params.edits.${pname}_sel.menu set sitems [${smenu} index end] for {set idx 0} {$idx <= $sitems} {incr idx} { set curcommand [${smenu} entrycget $idx -command] ${smenu} entryconfigure $idx -command "$curcommand ; \ magic::update_dialog $callback $pname $gencell_type $library" } } } } #---------------------------------------------------------- # Execute callback procedure, then run bounds checks #---------------------------------------------------------- proc magic::update_dialog {callback pname gencell_type library} { set pdefaults [${library}::${gencell_type}_defaults] set parameters [dict merge $pdefaults [magic::gencell_getparams]] if {[dict exists $parameters gencell]} { # Setting special parameter "gencell" forces the gencell to change type set gencell_type [dict get $parameters gencell] set pdefaults [${library}::${gencell_type}_defaults] set parameters [dict merge $pdefaults [magic::gencell_getparams]] } if {$callback != {}} { set parameters [$callback $pname $parameters] } if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ checkerr]} { puts stderr $checkerr } magic::gencell_setparams $parameters } #---------------------------------------------------------- # Add a standard checkbox parameter to the gencell window #---------------------------------------------------------- proc magic::add_checkbox {pname ptext parameters} { if [dict exists $parameters $pname] { set value [dict get $parameters $pname] } else { set value "" } set numrows [lindex [grid size .params.edits] 1] label .params.edits.${pname}_lab -text $ptext checkbutton .params.edits.${pname}_chk -variable magic::${pname}_val grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens grid .params.edits.${pname}_chk -row $numrows -column 1 -sticky wns set magic::${pname}_val $value } #---------------------------------------------------------- # Add a message box (informational, not editable) to the # gencell window. Note that the text does not have to be # in the parameter list, as it can be upated through the # textvariable name. #---------------------------------------------------------- proc magic::add_message {pname ptext parameters {color blue}} { if [dict exists $parameters $pname] { set value [dict get $parameters $pname] } else { set value "" } set numrows [lindex [grid size .params.edits] 1] label .params.edits.${pname}_lab -text $ptext label .params.edits.${pname}_txt -text $value \ -foreground $color -textvariable magic::${pname}_val grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens grid .params.edits.${pname}_txt -row $numrows -column 1 -sticky wns } #---------------------------------------------------------- # Add a selectable-list parameter to the gencell window #---------------------------------------------------------- proc magic::add_selectlist {pname ptext all_values parameters {itext ""}} { if [dict exists $parameters $pname] { set value [dict get $parameters $pname] } else { set value $itext } set numrows [lindex [grid size .params.edits] 1] label .params.edits.${pname}_lab -text $ptext menubutton .params.edits.${pname}_sel -menu .params.edits.${pname}_sel.menu \ -relief groove -text ${value} grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens grid .params.edits.${pname}_sel -row $numrows -column 1 -sticky wns menu .params.edits.${pname}_sel.menu -tearoff 0 foreach item ${all_values} { .params.edits.${pname}_sel.menu add radio -label $item \ -variable magic::${pname}_val -value $item \ -command ".params.edits.${pname}_sel configure -text $item" } set magic::${pname}_val $value } #---------------------------------------------------------- # Add a selectable-list parameter to the gencell window # Unlike the routine above, it returns the index of the # selection, not the selection itself. This is useful for # keying the selection to other parameter value lists. #---------------------------------------------------------- proc magic::add_selectindex {pname ptext all_values parameters {ival 0}} { if [dict exists $parameters $pname] { set value [dict get $parameters $pname] } else { set value $ival } set numrows [lindex [grid size .params.edits] 1] label .params.edits.${pname}_lab -text $ptext menubutton .params.edits.${pname}_sel -menu .params.edits.${pname}_sel.menu \ -relief groove -text [lindex ${all_values} ${value}] grid .params.edits.${pname}_lab -row $numrows -column 0 -sticky ens grid .params.edits.${pname}_sel -row $numrows -column 1 -sticky wns menu .params.edits.${pname}_sel.menu -tearoff 0 set idx 0 foreach item ${all_values} { .params.edits.${pname}_sel.menu add radio -label $item \ -variable magic::${pname}_val -value $idx \ -command ".params.edits.${pname}_sel configure -text $item" incr idx } set magic::${pname}_val $value } #------------------------------------------------------------- # gencell_defaults --- # # Set all parameters for a device. Start by calling the base # device's default value list to generate a dictionary. Then # parse all values passed in 'parameters', overriding any # defaults with the passed values. #------------------------------------------------------------- proc magic::gencell_defaults {gencell_type library parameters} { set basedict [${library}::${gencell_type}_defaults] set newdict [dict merge $basedict $parameters] return $newdict } #------------------------------------------------------------- # Command tag callback on "select". "select cell" should # cause the parameter dialog window to update to reflect the # selected cell. If a cell is unselected, then revert to the # default 'Create' window. #------------------------------------------------------------- proc magic::gencell_update {{command {}}} { if {[info level] <= 1} { if {![catch {set state [wm state .params]}]} { if {[wm state .params] == "normal"} { if {$command == "cell"} { # If multiple devices are selected, choose the first in # the list returned by "what -list". set instname [lindex [lindex [lindex [what -list] 2] 0] 0] magic::gencell_dialog $instname {} {} {} } } } } } #------------------------------------------------------------- # gencell_dialog --- # # Create the dialog window for entering device parameters. The # general procedure then calls the dialog setup for the specific # device. # # 1) If gname is NULL and gencell_type is set, then we # create a new cell of type gencell_type. # 2) If gname is non-NULL, then we edit the existing # cell of type $gname. # 3) If gname is non-NULL and gencell_type or library # is NULL or unspecified, then we derive the gencell_type # and library from the existing cell's property strings # # The device setup should be built using the API that defines # these procedures: # # magic::add_entry Single text entry window # magic::add_checkbox Single checkbox # magic::add_selectlist Pull-down menu with list of selections # #------------------------------------------------------------- proc magic::gencell_dialog {instname gencell_type library parameters} { if {$gencell_type == {}} { # Revert to default state for the device that was previously # shown in the parameter window. if {![catch {set state [wm state .params]}]} { if {$instname == {}} { set devstr [.params.title.lab1 cget -text] if {$devstr == "Edit device:"} { set gencell_type [.params.title.lab2 cget -text] set library [.params.title.lab4 cget -text] } else { return } } } } if {$instname != {}} { # Remove any array component of the instance name set instname [string map {\\ ""} $instname] if {[regexp {^(.*)\[[0-9,]+\]$} $instname valid instroot]} { set instname $instroot } set gname [instance list celldef [subst $instname]] set gencell_type [cellname list property $gname gencell] if {$library == {}} { set library [cellname list property $gname library] } if {$parameters == {}} { set parameters [cellname list property $gname parameters] } if {$gencell_type == {} || $library == {}} {return} if {$parameters == {}} { set parameters [${library}::${gencell_type}_defaults] } # If the default parameters contain "nocell", then set the # standard parameters for fixed devices from the instance if {[dict exists $parameters nocell]} { select cell $instname set arcount [array -list count] set arpitch [array -list pitch] dict set parameters nx [expr [lindex $arcount 1] - [lindex $arcount 0] + 1] dict set parameters ny [expr [lindex $arcount 3] - [lindex $arcount 2] + 1] dict set parameters pitchx [lindex $arpitch 0] dict set parameters pitchy [lindex $arpitch 1] } set ttext "Edit device" set itext $instname } else { set parameters [magic::gencell_defaults $gencell_type $library $parameters] set gname "(default)" set itext "(default)" set ttext "New device" } # Destroy children, not the top-level window, or else window keeps # bouncing around every time something is changed. if {[catch {toplevel .params}]} { .params.title.lab1 configure -text "${ttext}:" .params.title.lab2 configure -text "$gencell_type" .params.title.lab4 configure -text "$library" .params.title.glab configure -foreground blue -text "$gname" .params.title.ient delete 0 end .params.title.ient insert 0 "$itext" foreach child [winfo children .params.edits] { destroy $child } foreach child [winfo children .params.buttons] { destroy $child } } else { frame .params.title label .params.title.lab1 -text "${ttext}:" label .params.title.lab2 -foreground blue -text "$gencell_type" label .params.title.lab3 -text "Library:" label .params.title.lab4 -foreground blue -text "$library" label .params.title.clab -text "Cellname:" label .params.title.glab -foreground blue -text "$gname" label .params.title.ilab -text "Instance:" entry .params.title.ient -foreground brown -background white .params.title.ient insert 0 "$itext" ttk::separator .params.sep frame .params.edits frame .params.buttons grid .params.title.lab1 -padx 5 -row 0 -column 0 grid .params.title.lab2 -padx 5 -row 0 -column 1 -sticky w grid .params.title.lab3 -padx 5 -row 0 -column 2 grid .params.title.lab4 -padx 5 -row 0 -column 3 -sticky w grid .params.title.clab -padx 5 -row 1 -column 0 grid .params.title.glab -padx 5 -row 1 -column 1 -sticky w grid .params.title.ilab -padx 5 -row 1 -column 2 grid .params.title.ient -padx 5 -row 1 -column 3 -sticky ew grid columnconfigure .params.title 3 -weight 1 pack .params.title -fill x -expand true pack .params.sep -fill x -expand true pack .params.edits -side top -fill both -expand true -ipadx 5 pack .params.buttons -fill x grid columnconfigure .params.edits 1 -weight 1 } if {$instname == {}} { button .params.buttons.apply -text "Create" -command \ [subst {set inst \[magic::gencell_create \ $gencell_type $library {}\] ; \ magic::gencell_dialog \$inst $gencell_type $library {} }] button .params.buttons.okay -text "Create and Close" -command \ [subst {set inst \[magic::gencell_create \ $gencell_type $library {}\] ; \ magic::gencell_dialog \$inst $gencell_type $library {} ; \ destroy .params}] } else { button .params.buttons.apply -text "Apply" -command \ "magic::gencell_change $instname $gencell_type $library {}" button .params.buttons.okay -text "Okay" -command \ "magic::gencell_change $instname $gencell_type $library {} ;\ destroy .params" } button .params.buttons.reset -text "Reset" -command \ "magic::gencell_dialog {} ${gencell_type} ${library} {}" button .params.buttons.close -text "Close" -command {destroy .params} pack .params.buttons.apply -padx 5 -ipadx 5 -ipady 2 -side left pack .params.buttons.okay -padx 5 -ipadx 5 -ipady 2 -side left pack .params.buttons.close -padx 5 -ipadx 5 -ipady 2 -side right pack .params.buttons.reset -padx 5 -ipadx 5 -ipady 2 -side right # Invoke the callback procedure that creates the parameter entries ${library}::${gencell_type}_dialog $parameters # Add standard callback to all entry fields to run parameter bounds checks magic::add_check_callbacks $gencell_type $library # Make sure the window is raised raise .params } #-------------------------------------------------------------