tearoff.tcl 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. # tearoff.tcl --
  2. #
  3. # This file contains procedures that implement tear-off menus.
  4. #
  5. # Copyright (c) 1994 The Regents of the University of California.
  6. # Copyright (c) 1994-1997 Sun Microsystems, Inc.
  7. #
  8. # See the file "license.terms" for information on usage and redistribution
  9. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. #
  11. # ::tk::TearoffMenu --
  12. # Given the name of a menu, this procedure creates a torn-off menu
  13. # that is identical to the given menu (including nested submenus).
  14. # The new torn-off menu exists as a toplevel window managed by the
  15. # window manager. The return value is the name of the new menu.
  16. # The window is created at the point specified by x and y
  17. #
  18. # Arguments:
  19. # w - The menu to be torn-off (duplicated).
  20. # x - x coordinate where window is created
  21. # y - y coordinate where window is created
  22. proc ::tk::TearOffMenu {w {x 0} {y 0}} {
  23. # Find a unique name to use for the torn-off menu. Find the first
  24. # ancestor of w that is a toplevel but not a menu, and use this as
  25. # the parent of the new menu. This guarantees that the torn off
  26. # menu will be on the same screen as the original menu. By making
  27. # it a child of the ancestor, rather than a child of the menu, it
  28. # can continue to live even if the menu is deleted; it will go
  29. # away when the toplevel goes away.
  30. if {$x == 0} {
  31. set x [winfo rootx $w]
  32. }
  33. if {$y == 0} {
  34. set y [winfo rooty $w]
  35. if {[tk windowingsystem] eq "aqua"} {
  36. # Shift by height of tearoff entry minus height of window titlebar
  37. catch {incr y [expr {[$w yposition 1] - 16}]}
  38. # Avoid the native menu bar which sits on top of everything.
  39. if {$y < 22} { set y 22 }
  40. }
  41. }
  42. set parent [winfo parent $w]
  43. while {[winfo toplevel $parent] ne $parent \
  44. || [winfo class $parent] eq "Menu"} {
  45. set parent [winfo parent $parent]
  46. }
  47. if {$parent eq "."} {
  48. set parent ""
  49. }
  50. for {set i 1} 1 {incr i} {
  51. set menu $parent.tearoff$i
  52. if {![winfo exists $menu]} {
  53. break
  54. }
  55. }
  56. $w clone $menu tearoff
  57. # Pick a title for the new menu by looking at the parent of the
  58. # original: if the parent is a menu, then use the text of the active
  59. # entry. If it's a menubutton then use its text.
  60. set parent [winfo parent $w]
  61. if {[$menu cget -title] ne ""} {
  62. wm title $menu [$menu cget -title]
  63. } else {
  64. switch -- [winfo class $parent] {
  65. Menubutton {
  66. wm title $menu [$parent cget -text]
  67. }
  68. Menu {
  69. wm title $menu [$parent entrycget active -label]
  70. }
  71. }
  72. }
  73. if {[tk windowingsystem] eq "win32"} {
  74. # [Bug 3181181]: Find the toplevel window for the menu
  75. set parent [winfo toplevel $parent]
  76. while {[winfo class $parent] eq "Menu"} {
  77. set parent [winfo toplevel [winfo parent $parent]]
  78. }
  79. wm transient $menu [winfo toplevel $parent]
  80. wm attributes $menu -toolwindow 1
  81. }
  82. $menu post $x $y
  83. if {[winfo exists $menu] == 0} {
  84. return ""
  85. }
  86. # Set tk::Priv(focus) on entry: otherwise the focus will get lost
  87. # after keyboard invocation of a sub-menu (it will stay on the
  88. # submenu).
  89. bind $menu <Enter> {
  90. set tk::Priv(focus) %W
  91. }
  92. # If there is a -tearoffcommand option for the menu, invoke it
  93. # now.
  94. set cmd [$w cget -tearoffcommand]
  95. if {$cmd ne ""} {
  96. uplevel #0 $cmd [list $w $menu]
  97. }
  98. return $menu
  99. }
  100. # ::tk::MenuDup --
  101. # Given a menu (hierarchy), create a duplicate menu (hierarchy)
  102. # in a given window.
  103. #
  104. # Arguments:
  105. # src - Source window. Must be a menu. It and its
  106. # menu descendants will be duplicated at dst.
  107. # dst - Name to use for topmost menu in duplicate
  108. # hierarchy.
  109. proc ::tk::MenuDup {src dst type} {
  110. set cmd [list menu $dst -type $type]
  111. foreach option [$src configure] {
  112. if {[llength $option] == 2} {
  113. continue
  114. }
  115. if {[lindex $option 0] eq "-type"} {
  116. continue
  117. }
  118. lappend cmd [lindex $option 0] [lindex $option 4]
  119. }
  120. eval $cmd
  121. set last [$src index last]
  122. if {$last eq "none"} {
  123. return
  124. }
  125. for {set i [$src cget -tearoff]} {$i <= $last} {incr i} {
  126. set cmd [list $dst add [$src type $i]]
  127. foreach option [$src entryconfigure $i] {
  128. lappend cmd [lindex $option 0] [lindex $option 4]
  129. }
  130. eval $cmd
  131. }
  132. # Duplicate the binding tags and bindings from the source menu.
  133. set tags [bindtags $src]
  134. set srcLen [string length $src]
  135. # Copy tags to x, replacing each substring of src with dst.
  136. while {[set index [string first $src $tags]] != -1} {
  137. append x [string range $tags 0 [expr {$index - 1}]]$dst
  138. set tags [string range $tags [expr {$index + $srcLen}] end]
  139. }
  140. append x $tags
  141. bindtags $dst $x
  142. foreach event [bind $src] {
  143. unset x
  144. set script [bind $src $event]
  145. set eventLen [string length $event]
  146. # Copy script to x, replacing each substring of event with dst.
  147. while {[set index [string first $event $script]] != -1} {
  148. append x [string range $script 0 [expr {$index - 1}]]
  149. append x $dst
  150. set script [string range $script [expr {$index + $eventLen}] end]
  151. }
  152. append x $script
  153. bind $dst $event $x
  154. }
  155. }