#-----------------------------------------------------
# Magic/TCL general-purpose toolkit procedures
#-----------------------------------------------------
# Tim Edwards
# February 11, 2007
# Revision 0
#--------------------------------------------------------------
# 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 three procedures:
#
# 1. ${library}::${gencell_type}_params {gname} {...}
# 2. ${library}::${gencell_type}_check  {gname} {...}
# 3. ${library}::${gencell_type}_draw   {gname} {...}
#
# 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 checks the parameters for
# legal values.  The third draws the device.
#--------------------------------------------------------------

# 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} {
   menubutton ${framename}.titlebar.mbuttons.toolkit \
		-text $button_text \
		-relief raised \
		-menu ${framename}.titlebar.mbuttons.toolkit.toolmenu \
		-borderwidth 2

   menu ${framename}.titlebar.mbuttons.toolkit.toolmenu -tearoff 0
   pack ${framename}.titlebar.mbuttons.toolkit -side left
}

#----------------------------------------------------------------
# Add a menu item to the toolkit menu
#----------------------------------------------------------------

proc magic::add_toolkit_button {framename button_text gencell_type library} {
   set m ${framename}.titlebar.mbuttons.toolkit.toolmenu
   $m add command -label "$button_text" -command \
	"magic::gencell_params {} $gencell_type $library"
}

#-----------------------------------------------------
# Device selection
#-----------------------------------------------------

proc magic::gen_params {} {

    # Find selected item  (to-do:  handle multiple selections)
    set wlist [what -list]
    set clist [lindex $wlist 2]
    set ccell [lindex $clist 0]
    set cdef [lindex $ccell 1]
    if {[regexp {^(.*_[0-9]*)$} $cdef valid gname] != 0} {
       set library [cellname property $gname library]
       if {$library == {}} {
	  error "Gencell has no associated library!"
       } else {
          regexp {^(.*)_[0-9]*$} $cdef valid gencell_type
	  magic::gencell_params $gname $gencell_type $library
       }
    } else {
       # Error message
       error "No gencell device is selected!"
    }
}

#-----------------------------------------------------
# Add "Ctrl-P" key callback for device selection
#-----------------------------------------------------

magic::macro ^P magic::gen_params

#-------------------------------------------------------------
# gencell_setparams
#
#   Go through the parameter window and collect all of the
#   named parameters and their values, and generate the
#   associated properties in celldef "$gname".
#-------------------------------------------------------------

proc magic::gencell_setparams {gname} {
   set slist [grid slaves .params.edits]
   foreach s $slist {
      if {[regexp {^.params.edits.(.*)_ent$} $s valid pname] != 0} {
	 set value [$s get]
	 cellname property $gname $pname $value
      }
   }
}

#-------------------------------------------------------------
# gencell_getparam
#
#   Go through the parameter window, find the named parameter,
#   and return its value.
#-------------------------------------------------------------

proc magic::gencell_getparam {gname pname} {
   set slist [grid slaves .params.edits]
   foreach s $slist {
      if {[regexp {^.params.edits.(.*)_ent$} $s valid ptest] != 0} {
	 if {$pname == $ptest} {
	    return [$s get]
	 }
      }
   }
}

#-------------------------------------------------------------
# gencell_change
#
#   Redraw a gencell with new parameters.
#-------------------------------------------------------------

proc magic::gencell_change {gname gencell_type library} {
    if {[cellname list exists $gname] != 0} {
	if {[eval "${library}::${gencell_type}_check $gname"]} {
	    suspendall
	    pushstack $gname
	    select cell
	    erase *
	    magic::gencell_draw $gname $gencell_type $library
	    popstack
	    resumeall
	} else {
	    error "Parameter out of range!"
	}
    } else {
	error "Cell $gname does not exist!"
    }
}

#-------------------------------------------------------------
# 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 {gname gencell_type library} {
    suspendall
    if {[cellname list exists $gname] == 0} {
	cellname create $gname
	set snaptype [snap list]
	snap internal
	set savebox [box values]
	pushstack $gname
	magic::gencell_draw $gname $gencell_type $library
	popstack
	eval "box values $savebox"
	snap $snaptype
    }
    getcell $gname
    expand
    resumeall
}

#-------------------------------------------------------------
#-------------------------------------------------------------

proc magic::gencell_check {gname gencell_type library} {
    return [eval "${library}::${gencell_type}_check $gname"]
}

#-------------------------------------------------------------
#-------------------------------------------------------------

proc magic::gencell_draw {gname gencell_type library} {

   # Set the parameters passed from the window text entries
   magic::gencell_setparams $gname

   # Call the draw routine
   eval "${library}::${gencell_type}_draw $gname"

   # Find the namespace of the draw procedure and set propery "library"
   cellname property $gname library $library
}

#-----------------------------------------------------
#  Add a standard parameter to the gencell window
#-----------------------------------------------------

proc magic::add_param {gname pname ptext default_value} {

   # Check if the parameter exists.  If so, override the default
   # value with the current value.

   set value {}
   if {[cellname list exists $gname] != 0} {
      set value [cellname property $gname $pname]
   }
   if {$value == {}} {set value $default_value}

   set numrows [lindex [grid size .params.edits] 0]
   label .params.edits.${pname}_lab -text $ptext
   entry .params.edits.${pname}_ent -background white
   grid .params.edits.${pname}_lab -row $numrows -column 0
   grid .params.edits.${pname}_ent -row $numrows -column 1
   .params.edits.${pname}_ent insert end $value
}

#-----------------------------------------------------
# Update the properties of a cell
#-----------------------------------------------------

proc magic::update_params {gname ptext default_value} {
}

#-------------------------------------------------------------
# gencell_params ---
# 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
#-------------------------------------------------------------

proc magic::gencell_params {gname {gencell_type {}} {library {}}} {

   if {$gname == {}} {
      set pidx 1
      while {[cellname list exists ${gencell_type}_$pidx] != 0} {
	  incr pidx
      }
      set gname ${gencell_type}_$pidx

      set ttext "New device"
      set btext "Create"
      set bcmd "magic::gencell_create $gname $gencell_type $library"
   } else {
      if {$gencell_type == {}} {
	 set gencell_type [cellname property ${gname} gencell]
      }
      if {$library == {}} {
	 set library [cellname property ${gname} library]
      }

      set ttext "Edit device"
      set btext "Apply"
      set bcmd "magic::gencell_change $gname $gencell_type $library"
   }

   catch {destroy .params}
   toplevel .params
   label .params.title -text "$ttext $gname"
   frame .params.edits
   frame .params.buttons
   pack .params.title
   pack .params.edits
   pack .params.buttons

   button .params.buttons.apply \
	-text "$btext" \
	-command [subst { $bcmd ; \
	.params.buttons.apply configure -text Apply}]
   button .params.buttons.close -text "Close" -command {destroy .params}

   pack .params.buttons.apply -padx 10 -side left
   pack .params.buttons.close -padx 10 -side right

   # Invoke the callback procedure that creates the parameter entries

   eval "${library}::${gencell_type}_params $gname"
}

#-------------------------------------------------------------
