# centerWin --
#
#      Centers a window (win) in its toplevel (ow). 
#      Improved version of one found in Midnight Commander.
#
proc centerWin1 {win {ow {}}} {
  if {1} {
    catch {
      #wm withdraw $win
      waitForIdle
      #set top [wm attributes . -topmost]
      if {$ow == {}} { set ow [winfo toplevel $win] }
      foreach {c r} {y reqheight x reqwidth} {set cen$c [winfo $r $win]}
      # Can't use winfo geo here as its x,y are relative to its parent
      foreach {id r} {pdx width pdy height px rootx py rooty} {set $id [winfo $r $ow]}
      foreach c {x y} {set $c [expr \$p$c+((\$pd$c-\$cen$c)/2)]}
      wm geometry ${win} +$x+$y
    }
  } else {
    puts "doing PlaceWindow $win widget $ow"
    ::tk::PlaceWindow $win widget $ow
  }
}
# problems with above...
# It uses winfo to get x & y, but that does not account for the borders...

# In this version we accept three options for ow:
# nil    => use top level window but if this is a toplevel center in '.'
# window => center in named window
# area   => center in the area (area should be a list of xmin xmax ymin ymax)
#           note this will error by ~1/2 the bottom border and the right border
#           If these values are known you may subtract them from xmax & ymax.

# good to know stuff...
# On MSW systems wm geo and winfo geo always return the same size on a toplevel.
# This size does NOT include the window managers frame.
# It also does NOT inclued the menu optionally added by the -menu option of toplevels

# The position returned by winfo is the position of the toplevel NOT the wm frame
# EXCEPT on MSW where wm geo and winfo geo return the same, however,
# winfo rootx and winfo rooty do return the location of our window and not the frame.
# The position returned by wm is the position of the wm frame.
# The difference in these positions is the wm border AND the -menu size
# It is relatively easy to get the title bar and -menu sizes as well as the left border
# However, the bottom and right borders require asking the wm about the true size.
# We assume left, right and bottom to be the same.
# One might try zoom and override with wm geo.
# If the window is grided (wm grid returns stuff) the wm geo size is in characters AND
# seems to include only the included text window. winfo geo/rootx/rooty are not affected
# by this. This version takes care of the -menu issue, however there will be a small
# error (~1/2 the bottom window border) when positing using the third option.
# If the target window (where we want the window to land) is not a toplevel:
# winfo x and winfo y give numbers relative to the parent window while
# winfo rootx and winfo rooty give screen relative numbers.

# here we do the data collections for a toplevel window..

proc tlbd {w} {
 
  if {[winfo toplevel $w] != $w} {return [list 0 0 [winfo rootx $w] [winfo rooty $w]]}
  if {! $::MSW} {
    lassign [split [wm geo $w] x+] -> -> rx ry
  } else {
    set rx [winfo x $w]
    set ry [winfo y $w]
  }
  set bd [expr {[winfo rootx $w] - $rx }]
  set hd [expr {[winfo rooty $w] - $ry - $bd}]
  return [list $bd $hd $rx $ry]
}

proc centerWin {tw  {wo {}}} {
  realWaitForIdle
  frputs tw ow
  if {$wo == {}} {
    set wo [winfo toplevel $tw]
    if {$wo == $tw} {
      set wo "."
    }
  }
  # O is the window we are centering into, t is the window to be moved (centered)
  if {[string index $wo 0] == "."} {
    lassign [split [winfo geo $wo] x+] sizeox sizeoy mox moy
    lassign [tlbd $wo] ob oh ox oy
  } else {
    # xmin xmax ymin ymax
    lassign $wo mox sizeox moy sizeoy
    foreach xy {x y} {
      set sizeo$xy [expr {[set sizeo$xy] - [set mo$xy]}]
      set o$xy [set mo$xy]
    }
    lassign {0 0} ob oh
  }
  lassign [split [winfo geo $tw] x+] sizetx sizety mtx mty 
  lassign [tlbd $tw] tb th

  foreach xy {y x} {
    set $xy [expr {[set o$xy] + $ob - $tb +\
                       ([set sizeo$xy] - [set sizet$xy] + $oh - $th) / 2}]
    frputs tw wo o$xy ob tb oh th sizeo$xy sizet$xy $xy
    set oh [set th 0]
  }
   
  wm geometry ${tw} +$x+$y
  focus $tw
  return [list  $x $y]
}
#
# centerMouse2
#
# This function moves the mouse pointer, by default to the 
# center of a given widget.
#
# parms:
#        w     The window to move the pointer to
#        wmgeo That windows geometry (WxH+x+y) (optional)
#              if not supplied [winfo geom $w] is used.
#              If that window does not exist, we just return.
#              Only the W & H numbers are used so this parm
#              may be supplied as: ${x}x${y}.  The mouse
#              will be moved to x: W/2 y: H/2, i.e centered
#              in the window or the x,y.  There is no
#              restriction that the target be in the given 
#              window, but the position is relative to that
#              window. 

# It is assumed that this will be used after positioning the window 
# and, usually with focus.  This means that there is a very real chance
# that the movement has not yet been done AND [update] in any of 
# its forms will not fix this.  The solution that seems to work is
# to use an [after] statement so we take care of that below...

# Do note that if you want to use the 'now' version, the second parm is
# required.
        

proc centerMouse2 {w {wmgeo ""}} {
  if {$wmgeo=="" && [catch "winfo geom $w" wmgeo] != 0} {return}
  after idle "centerMouse2now $w $wmgeo"
}

proc centerMouse2now {w wmgeo} { 
  lassign [split $wmgeo x+] x y;
  #puts "x $x y $y"
  event generate $w <Motion> -warp 1 -x [expr $x/2] -y [expr $y/2]
}
