# <20240613.1502.20>
# This is a 'smart' take off on tk_dialog.  It is set up
# so that we can use colors in the text, center the window
# above the master (and keep it above), provide variable
# number of buttons with out changing the call sequence
# (we allow unused buttons to be specified and then not used).
#
#  parms
#  win    the desired window name (if one already exists it is destroyed)
#         If 'win' is not a toplevel window AND 'win's parent exists AND
#         is not "." AND 'buttonCount' is not 0 a frameless window is built    
#         with all the given options. (Its name is $win). It is up to
#         the caller to manage from then on. Usually this window will be
#         put in the parent in someway. For example if the parent is 
#         managed by the 'grid' command, the script might be:        
#         grid $win -in [winfo parent $win]
#         The return in this case is the same as in the "debug" option,
#         i.e. the vwait variable name.
#  master win will be centered above master and will be destroyed when
#         master is.
#  title  title for win
#  text   a list of strings for the windows query area
#         the strings will be concationated in the window
#         the even entries will be in standard text and
#         the odd entries in 'select' text
#         empty strings may be used to switch as needed.
#         The window height will be as needed up to 30 lines.
#         If more that 30 lines are needed a scroll bar will appear.
#         You can change this, see 'scroll' under args.
#         This argument is ignored if you code 'textfun' in the 'args'
#         options below.
#         If the resulting text part of the widget is empty, i.e. text is {}
#         and 'textfun' does not add text, the text part is removed from the
#         widget.
#  default button number (starting from 0) of the default button
#          -1 implies no default.  A carrage return in the window
#          will return this number.
#  buttonCount If the number of buttons to build.
#              > 0  Build 'buttonCount' buttons as specified by 'buttons'.
#              =  0 Build a frameless text only window.  This window will
#                   need  to be destroyed by the caller or destruction of
#                   the master  or by mouse <1> click.  The window will by
#                   default flash in two ways:
#                       1) a flat border and configured bg color
#                       2) a solid border and a 'flash' bg color
#                   There are 4 configure options for the flash.  A flash
#                   time of '0' will turn off flashing (as will flashon == 0).
#                   See the options below under 'args'.          
#  buttons a list of button labels.  Should be as long as 'buttonCount'
#          but may be longer (if shorter than button count, blank buttons
#          are created). Each button label may be a list as follows:
#          {name {'other'}}             just a button, pressing will
#                                       close the window and return this
#                                       buttons number.
#          {name {-command {script} 'other'}}     Button press will run script.
#                                                 The script may close the window by
#                                                 setting "::smart_dialog$win.text"
#                                                 to the desired smart_dialog return
#                                                 (usually the button number).
#          {name {-variable globalvar 'other'}}   Button becomes a checkbutton 
#                                                 with variable globalvar
#                                                 which will assumed values
#                                                 'true' or 'false'.
#          {{name} {-textvariable globalvar 'other'}} Builds an 'entry' window
#                                                 below the text window with
#                                                 'globalvar' as its
#                                                 '-textvariable'.
#                                                 Bindings for <Return> and
#                                                 <KB_Return>  will close the
#                                                 window and return the button
#                                                 number. <Escape> will close
#                                                 the window and return -1.
#                                                 'name' (if not "") will create
#                                                 a label to the left of the
#                                                 entry window.
#          {{name} {-values valueslist 'other'}}  Builds a 'combobox' which is
#                                                 much like the -textvariable button
#                                                 above, but which also has a
#                                                 pop-down list (valueslist) of
#                                                 possible entries. 'other' must
#                                                 include a -textvariable option to
#                                                 capture the input. The combobox is a
#                                                 mega widget. Option commands to it
#                                                 can change the fg & bg colors. The
#                                                 -edit <bool> option, if true allows
#                                                 entries only from the dropdown. This is
#                                                 done by disabling the 'entry' box
#                                                 which also changes its colors
#                                                 'disabledbackground' and
#                                                 'disabledforeground' which are in the
#                                                 child window '.entry'.
#                                                 
#          {{name} {-text {text} 'other'}}        Builds a label only entry below
#                                                 the text window. If 'arrange'
#                                                 (see below)is set to provide 1
#                                                 entry per linein the (-text,
#                                                 -texvariablet, -value)group, the
#                                                 'name' is ignored and the label
#                                                 will span the whole width of the
#                                                 window. If 'arrange' is to put
#                                                 more than one element on a line
#                                                 and the 'name' is 'fullspan' then
#                                                 this'-text' line will build a
#                                                 'label' entry that spans the
#                                                 remainder of the line being build
#                                                 (i.e. if the firstentry it will
#                                                 span the whole line, if other than
#                                                 the first entry it will span the
#                                                 remainder of the line). On the
#                                                 otherhand, if 'name' is not
#                                                 'fullspan' the label will span
#                                                 only the alloted column.Thus it
#                                                 may be used to generate column
#                                                 heads, for example.
#          In all cases 'other'  may be empty or may contain other options for
#          the given widget (-width xx might be good for entry widgets). 
#          In the first case 'other' must not start with '-command, 
#          -variable or -textvariable.
#
#  Groups  There are three groups, each of which forms a part of the window
#          Group 1 is the text window, 2 consists of the -textvariable, -value
#          and -text "buttons" and group 3 is the rest of the "buttons".
#          By default these appear in order, however, the "arrange" option
#          (see below may be used to change the order).
#
#  args    (optional) one or more lists that contains info on extra window
#          decorations this will be used with the text window (which is of
#          type text and may be any option a text window supports. Most
#          likely this  will be used to set up select colors. Useful things:
#          -background               color      (default data base)
#          -flash                    <on/off time in ms> (500 (0 turns off))
#          -flashborderwidth         n          (widget default, i.e. 1)
#          -flashcolor               color      (red)
#          -flashon                  bool       (0 if button count > 0)
#          -font                     font       (data base)
#          -foreground               color      (default data base)
#          -height                   nnn        (as needed by 'text' but > 30
#                                               will create a scrolled window
#                                               of 30 lines)
#          -inactiveselectbackground color      (default data base)
#          -selectforeground         color      (default  data base)
#          -state                    disabled   (default enabled) See 'text' manpage

#          arrange                   {num list} "num list" is a list of three
#                                               numbers which can change the 
#                                               order of the "groups" (see
#                                               above) and set the number of buttons
#                                               in each line. The first digit in
#                                               each number is the group and the
#                                               remaining digits specify the number
#                                               of buttons in a line in this group.
#                                               Default is {1 2 3}.
#                                               {3 2 1} would put the buttons
#                                               on top, and text on the bottom.
#                                               {2 1 3} puts the -text, -value and
#                                               -textvariable on top, text
#                                               in the middle and buttons on 
#                                               the bottom. These numbers become
#                                               the "row" numbers for each group.
#                                               {1 25 32} puts the -text, -value  and
#                                               -textvariable buttons in rows of 5
#                                               and the buttons in rows of 2 per line.
#                                               NOTE: In 'Group 2' the 'name' part is
#                                               ignored if more than one button is
#                                               requsted per row.
#          bind                      {script}   to bind to buttons or text
#                                               button names are 'win.no' where
#                                               no is the button number. The
#                                               text widget is 'win.text' The following
#                                               bindings are the default:
#                                               win.text <KeyPress>, <KeyRelease>
#                                               and <Leave> to "break"
#                                               win.text <Enter> "focus win.text \; break"
#          debug                      bool      1 causes return with out waiting
#                                               for input/etc. In this case the value
#                                               returned is the global that is usually
#                                               "vwait"ed on. It will be set when the
#                                               window is destroyed (-1) or a button is
#                                               pushed (button number). In this case
#                                               the user needs to destroy the window.
#          grip Not implemented yet  string     if <string> contains ("sw" "se") put in a
#                                               sizing grip in lower (left right)
#                                               of the window (can ask for both)
#          maxw                      int        over ride max window width pixals
#                                               (default is master window width)
#          position                  {script}   This function is called to
#                                               position the smart_dialog window.
#                                               Two arguments are passed, the
#                                               window name and the master window
#                                               name. By default "centerWin" is
#                                               called. This function is called after 
#                                               the window is set up and may also be used
#                                               to tweak other things. See bind above
#                                               for window names.
#          scroll                    n          (default 30) Height >= 'n' 
#                                               will limit to n
#                                               with a scroll bar
#          stackbuttons              bool       arrange buttons in one column  rather
#                                               than the default row. This interacts with
#                                               the 'arrange' option above in that if
#                                               'arrange' only is set the buttons will be
#                                               across and then down, but with both they
#                                               will be down and then across.
#          tag                       {tag config} (no default)
#                                               The tag configure allows you to configure
#                                               a tag (named tag) that is used on every
#                                               line of text. One example is:
#                                               {tag {config tag -justify center}}
#                                               which will cause lines to be centered
#                                               in the window.
#          textfun                   {script}   script is post pended with the
#                                               text window name and called 
#                                               instead of putting 'text' in
#                                               the window. This function can
#                                               set up tags on the entries. These
#                                               tags can bind to funtions which can
#                                               force the window to close and return "x"
#                                               by writing "x" to ::smart_dialogBut$w
#                                               where $w 'win.text'.
#          focus                     buttonnum  This will cause 'buttonnum' to get focus
#                                               when ever the widget is <Enter>'ed and
#                                               any other button does not have focus.
#
#
#  smart_dialog returns the number of the button pressed or -1 if the window is
#               destroyed before its time.
#
#          smart_dialog will build a window with a minimum width of that 
#          required for the specified buttons and a maximum width of 
#          what ever the masters width is (as long as it is greater than
#          the above minimum.
#
#          This widgit uses centerWin
#
#  A comment on coroutines: The vwait variable (::smart_dialogAfter$w) is
#  defined as a global which is NOT dependent on the core_auto redefing of
#  'global'. This is as it should be because the window name space is global
#  and by tagging our vwait var with the window name we are assured of a
#  true unique global.
#
proc smart_dialog {win master title text {default 0} {buttonCount 0} \
		       {buttons {} } args} {
  # check if win parent exists and is not toplevel
  set wp [join [lrange [split $win .] 0 end-1] .]
    # frputs win wp 
  destroy $win
  set w $win.text
  set flashOn [expr {$buttonCount == 0}]
  catch {after cancel $::smart_dialogAfter$w}
  while {[winfo exists $win]} {waitForIdle;puts "[incr foo]"}
  if {![winfo exists $wp] || $wp == "." || $flashOn} {
    toplevel $win -class Dialog
    wm iconname $win Dialog
    wm att $win -alpha 0.0
    wm title $win $title
    set wp {}
  } else {
    frame $win
  }
  # frputs buttons wp
  # protect against pending destruction of "master"
  #update idletasks
  if {$master != "."} {
    bind $master <Destroy> "+destroy $win"
  }
  #  puts "$text"
  set color red
  # we defer setting text state until after we put the text in the wiget
  set state normal
  set flash 500
  set position {centerWin}
  lassign {0 1 2} g1 g2 g3
  text $w \
      -height 1 \
      -wrap word \
      -setgrid [expr {$wp == {}}]
  bind $w <Destroy> "set ::smart_dialogBut$w -1"
  frame $win.mid
  # For reasons we do not understand, this must be here or we will not
  # be able to get this windows width to drive the master window width
  # We would prefer to have included these options with the -row, below.
  grid $w -column 0 -sticky nsew

  if {!$flashOn} {
    frame $win.bot
    $win.bot configure -relief raised -bd 1
    #grid $win.bot -row $g3 -columnspan 2 -sticky sew 
    grid anchor $win.bot center
  } else {
    wm withdraw $win
   # wm overrideredirect $win 1
  }
  lassign 0 width entrywindows butGrid valGrid textGrid
  #waitForIdle
  lassign {0 1 2} g1 g2 g3
  lassign [split [winfo geo $master] "x"] maxw
  set maxheight 30
  # frputs win
  for {set co 0} {$co < $buttonCount ||\
		      ($buttonCount < 0 &&\
			   $co < [llength $buttons])} {incr co} {
    #set extra [lassign [lindex $buttons $co] name]
    lassign [lindex $buttons $co] name extra
    lassign $extra option
    frputs extra name option "[lindex $buttons $co] "
    # we don't want to require double brackes for button
    # names if s/he is not trying to include an option so..
    # But then again for consistancy...
    if {[string index $extra 0] != "-" } {
      set extra {}
      set name2 [lindex $buttons $co]
      if {[string range $name2 1 end-1] != $name} {
	set name $name2
      }
    }
    set r 0
    switch $option {
      -text {
	lappend entrywindows $co
	label $win.$co -width 0
 	set r [catch "$win.$co config $extra" ho]
	grid $win.$co -in $win.mid -row $co -column 0 -columnspan 2 -sticky ew
	lappend valGrid $co
	if {$name == "fullspan"} {
	    lappend textGrid $co
	}
      }
      -variable {
	checkbutton $win.$co -text $name -width 0
	set r [catch "$win.$co config $extra" ho]
	$win.$co config -borderwidth 3 -relief raised
        $win.$co config -anchor w
 	lappend butGrid $co
	# add in the width of the check box
	incr width 3
	if {$default == $co} {
	  set default -1
	}
      }
      -values -
      -textvariable {
	lappend entrywindows $co
	if {$option == "-textvariable"} {
	  entry $win.$co -width 0
	} else {
	  package require combobox
	  combobox::combobox $win.$co -width 0
	  # we absorbe a syntax change for the combo box
	  set extra [lassign $extra -> vals]
	  $win.$co list insert end {*}$vals
	  
	  # $win.$co configure -font\
	  #     [[ttk::combobox::PopdownWindow $win.$co].f.l cget -font]
	}
	label $win.label$co -text $name
	grid $win.label$co -in $win.mid -row $co -column 0 -sticky e
	grid $win.$co -in $win.mid -row $co -column 1 -sticky ew
	if {$wp == {}} {
	  bind $win.$co <Return> "set ::smart_dialogBut$w $co"
	  bind $win.$co <KP_Enter> "set ::smart_dialogBut$w $co"
	  bind $win.$co <Escape> "set ::smart_dialogBut$w -1"
	}
 	set r [catch "$win.$co config $extra" ho]
	frputs co extra ho
	$win.$co icursor end
	$win.$co xview moveto 1.
 	lappend valGrid $co
    }
      -command -
      default {
	button $win.$co  -width 0\
	    -text $name \
	    -command "set ::smart_dialogBut$w $co"
	$win.$co config -borderwidth 3 -relief raised
	$win.$co config -default [expr {$co == $default ? "active" : "normal"}]
	set r [catch "$win.$co config $extra" ho]
	lappend butGrid $co
      }
    }
    if {$r != 0} {frputs "button command >$win.$co config $extra Returns $ho "}
  }
  set computedButtonCount $co
  # These need to be here so thay can be overridden by 'decor' ops
  bind $w <KeyRelease> {break}
  bind $w <KeyPress> {break}
  # Leaving motion allows selection...
  # bind $w <Motion> {break}
  bind $w <Leave> {break}
  bind $w <Enter> "focus $w \; break"
  # We want to allow the std args (pairs of arg/val) i.e.: [list arg/val arg/val ...]
  
  # And a set of lists wrapped by the args list, i.e:
  #[list [list arg/val] [list arg/val] [list arg/val]]

  if {[llength [lindex $args 0]] == 1} {
    set decor $args
  } else {
   set decor {}
   foreach arg $args {
      lappend decor {*}$arg
    }
  }
  lassign {0 1 2} debug colConf maxMidCol
  foreach {op val} $decor {
    set r 0
    switch $op {
      -state {set state $val}
      -flash {set flash $val}
      -flashcolor {set color $val}
      -flashborderwidth {$w config -borderwidth $val}
      -flashon {set flashOn $val}
      focus   {
	if {[winfo exists $win.$val]} {
	  bind $win <Enter> "focus $win.$val"
	}
      }
      maxw    {set maxw $val}
      bind    {set r [catch "bind {*}$val" ho]}
      tag     {set r [catch "$w $op $val" ho]}
      debug   {set debug [expr {$val == {} ? 1 : $val}]}
      grip    {set gripRq $val}
      scroll  {set maxheight $val}
      textfun {set textfun $val}
      position {set position $val}
      stackbuttons {set stack [expr {$val == {} ? 1 : $val}]}
      arrange {
	lassign $val g1 g2 g3
	# set error if not numbers
	foreach gn [list $g1 $g2 $g3] {
	  if {! [regexp {^[0-9]+$} $gn]} {
	    set r 1
	    set ho "$gn is not a numeric"
	    lassign {1 2 3} g1 g2 g3
	    break
	  }
	}
      }
      default {
	set r [catch "$w config $op \"$val\"" ho]
      }
    }
    if {$debug && $r != 0} {
      frputs r op val win ho
    }
    frputs g1 g11 g2 g21 g3 g31
    # Redo the col and row numbers for the -text, -values & -textvariable entries
    set maxMidCol [string range $g2 1 end]
    if {$maxMidCol ni {{} {1}}} {
      lassign {0 0} row col
      foreach ent $valGrid {
	grid $win.$ent -in $win.mid -row $row -column $col\
	    -columnspan [expr {$ent in $textGrid ? $maxMidCol -$col : 1}]
	if {[winfo exists $win.label$ent]} {
	  grid forget $win.label$ent
	}
	if {[incr col] == $maxMidCol || $ent in $textGrid} {
	  incr row
	  set col 0
	}
      }
      set colConf "all"
    } else {
      set maxMidCol 2
    }
    if {$r != 0} {frputs "args $w config \{$op $val\}  Returns $ho "}
  }
  
  foreach nm {g1 g2 g3} {
    set ${nm}1 [string index [set $nm] 0]
  }
 

  grid $w -column 0 -row $g11 -sticky nsew
  grid rowconfig $win    $g11 -weight 1
  grid columnconfig $win 0     -weight 1
  grid columnconfig $win.mid $colConf -weight 1
  #grid $win.mid -in $win -row 1 -column 1 -sticky ewns
  if {0} {
    # lets use a scroll bar to control this...
    #set height $maxheight
    scrollbar $win.mid.scroll  -relief sunken -command "$win.mid yview"
    $win.mid config -yscrollcommand "$win.mid.scroll set"
    grid $win.mid.scroll -column 40 -in $win.mid -row $g1 -sticky nse -rowspan 40
  }
  grid $win.mid -in $win -row $g21 -sticky ewns -columnspan $maxMidCol
  if {!$flashOn} {
    grid $win.bot -row $g31 -sticky sew -columnspan 2
  }

  # grid the check and normal buttons
  lassign {0 0 0} pad col row
  set maxCol [string range $g3 1 end]
  if {$maxCol == {}} {
    set maxCol 1000
  }
  foreach cmd $butGrid {
    set rs [expr {[info exists stack] ? \
		      "-column $row -sticky ew -row" :\
		      "-row $row -sticky news -column"}]
    grid $win.$cmd -in $win.bot {*}$rs $col -padx $pad -pady $pad
    if {[incr col] == $maxCol} {
      set col 0
      incr row
    }
  }
  # The following wait verfied as needed!
  set rw [realWaitForIdle]; #frputs rw
  # frputs [realWaitForIdle]
  if {!$flashOn} {
    for {set co 0} {$co < $computedButtonCount} {incr co} {
      set butfont  [$win.$co cget -font]
      # It seems the text is padded with 3 spaces front & back & we 
      # left and right pad by "$pad" and have borders of 3 each side -> 16
      if {$co ni $entrywindows} {
	set thiswidth [expr {[font measure $butfont \
				  "   [lindex $buttons $co 0]   "] + $pad + $pad + 6}]
	if {[info exists stack] && $stack} {
	  set width [expr {max($width,$thiswidth)}]
	} else {
	  incr width $thiswidth
	}
      } else {
	set maxcw [expr {$maxw / [font measure $butfont "0"]}]
	set rw [realWaitForIdle]
	# frputs rw
	if {[$win.$co cget -width] > $maxcw} {
	  $win.$co config -width $maxcw
	}
      }
    }
  }
  # width is now the min width we want to use...in pixels
  if {[info exist textfun] } {
    eval "$textfun $w"
  } else {
    foreach {std hig} $text {
      $w insert insert "$std"  tag 
      $w insert insert "$hig" [list  tag sel col.first col.last]
    }
  }
  
  $w config -state $state
  # The window height (and width) depends on correctly reading back
  # the text we just sent. Verified as needed!
  set rw [realWaitForIdle];frputs rw
  #$w sync
  set tmp [split [$w get 1.0 end] "\n"]
  set font [$w cget -font]
  set mx 0
  # we use butWidth as the min window width, the masters width as the max
  set maxw [expr {max($maxw,$width)}]
  set maxfudge [expr {max( (($maxw * 9) / 10), 1)}]
  set charsz [font measure $font "0"]
  set height -1
  foreach line $tmp {
    incr height
    set thisw [font measure $font -displayof $w $line]
    # The following accounts for line wrap
    if {$thisw > $maxw} {
      incr height [expr {$thisw / $maxfudge}]
      # puts "$height [expr {$thisw / $maxfudge}]"
      set width $maxw
    } else {
      set width [expr {max($width,$thisw)}]
    }
  }
  # Really do need to wait here.
  set rw [realWaitForIdle];frputs rw
  # waitForIdle
  set height [expr {max($height,[$w cget -height])}]
  if {$height > $maxheight} {
    # lets use a scroll bar to control this...
    set height $maxheight
    scrollbar $win.scroll  -relief sunken -command "$w yview"
    $w config -yscrollcommand "$win.scroll set"
    grid $win.scroll -column 1 -in $win -row $g1 -sticky nse
  }
  #puts "setting height $height width [expr {($width / $charsz) +1}]"
  $w config -height $height -width [expr {($width / $charsz) +1}] 
  set rw [realWaitForIdle]; # frputs rw
  # waitForIdle
  if {$tmp == {{} {}} } {
    # remove the text window if it is empty
    grid remove $w
  }
#  $w config -state disabled
  if {$default >= 0} {
    bind $w <Return> " 
	    $win.$default configure -state active -relief sunken
	    waitForIdle
	    after 100
	    set ::smart_dialogBut$w $default
	"
  }
  #  bind $w <Button> {break}
  # this wm geo command is a mystery to me????
  # mystery solved: wm grid baseWidth & baseHeight (wid hig) are the
  # requested width and height in grid units and since we are grided
  # grid units is what 'wm geo' takes. I.e. the 'wm geo' forces the
  # right size window.
  frputs wp
  if {$wp == {}} {
    lassign [wm grid $win] wid hig
    frputs win wid hig
    wm geo $win ${wid}x$hig
    while {1} {
      lassign [split [wm geo $win] x+] nw nh
      # frputs wid nw hig nh
      if {($nw == $wid && $nh == $hig) || [incr xyzzy] > 1000} {break}
      set rw [realWaitForIdle];frputs rw
      # waitForIdle
    }
    # frputs xyzzy wh "[wm state $win] [wm geo $win] "
  }
  #  bind $w <<Modified>> "$w edit undo"
  if {$wp == {}} {
    # grow box
    # Not sure yet on how to handle grips
    # Possibly we need to add one or two sub windows to .bot (say .botl and .botr)
    # and put the grips in there?
    if {[info exist gripRq] && 0} {
      set grow [expr {max($g11, $g21)}]
      if {!$flashOn} {
	set grow [expr {max($grow,$g31)}]
      }
      if {[string match -nocase *se* $gripRq]} {
	set gb [segrip $w]
	grid $gb -row $grow -column 1 -sticky se
      }
      if {[string match -nocase *sw* $gripRq]} {
	set gb [swgrip $w]
      }
    }
    catch {wm deiconify $master}
    eval $position $win $master
    wm transient $win $master
    wm att $win -alpha 1.0
  } else {
    # This is a sub window, we are done..
    return ::smart_dialogBut$w
  }
  if {$flashOn} {
    # We had the following much earlier, but it seem much more reliable here.
    wm overrideredirect $win 1
    bind $w <1> "destroy $win \; \
                 catch \"after cancel \[set ::smart_dialogAfter$w]\" \; break"
    if {$flash != 0 && $flashOn} {
      set bgcolor [$w cget -bg]
      smart_dialog_flash $w $flash $color $bgcolor 1
    }
    raise $win
    # frputs "[clock microseconds] "
    wm deiconify $win
    eval $position $win $master
 
    return
  }
  set oldFocus [focus]
  set oldGrab [grab current $w]
  if {$oldGrab != ""} {
    ##set grabStatus [grab status $oldGrab]
    grab release $oldGrab
  }
  set rw [realWaitForIdle]; # frputs rw
  # waitForIdle
  if {$default != "-1"} {
    focus -force $win.$default
  } else {
    focus -force $w
  }
  catch {after cancel [set ::smart_dialogAfter$w]}
  if {$flash != 0 && $flashOn} {
    set bgcolor [$w cget -bg]
    smart_dialog_flash $w $flash $color $bgcolor 1
  }
  if {$debug} {return ::smart_dialogBut$w}
  # frputs  ::smart_dialogBut$w
  vwait ::smart_dialogBut$w
  # while {![info exists ::smart_dialogBut$w]} {update}
  catch {focus $oldFocus}
  if {$oldGrab != ""} {
    grab $oldGrab
  }
  if {[catch "set ::smart_dialogBut$w" ex] !=0} {set ex -1}
  catch "destroy $win"
  catch "unset ::smart_dialogBut$w"
  # Lets remove the destroy command from the master window....
  return $ex
}

proc smart_dialog_flash {w flash color bgcolor onoff} {
  catch {after cancel [set ::smart_dialogAfter$w]}
  if {[winfo exists $w]} {
    if {$onoff} {
      set onoff 0
      $w config -relief solid
      $w config -bg $color

    } else {
      set onoff 1
      $w config -relief flat
      $w config -bg $bgcolor
    }
    set ::smart_dialogAfter$w \
	[after $flash "smart_dialog_flash $w $flash $color $bgcolor $onoff"]
  }
}
