|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
package require Tk |
|
|
|
namespace eval ::tkdnd { |
|
variable _package_dir {} |
|
variable _topw ".drag" |
|
variable _tabops |
|
variable _state |
|
variable _x0 |
|
variable _y0 |
|
variable _platform_namespace |
|
variable _drop_file_temp_dir |
|
variable _auto_update 1 |
|
variable _dx 3 |
|
variable _dy 3 |
|
|
|
variable _windowingsystem |
|
|
|
if {[info exists ::TKDND_DEBUG_LEVEL]} { |
|
variable _debug_level $::TKDND_DEBUG_LEVEL |
|
} elseif {[info exists ::env(TKDND_DEBUG_LEVEL)]} { |
|
variable _debug_level $::env(TKDND_DEBUG_LEVEL) |
|
} else { |
|
variable _debug_level 0 |
|
} |
|
|
|
bind TkDND_Drag1 <ButtonPress-1> {tkdnd::_begin_drag press 1 %W %s %X %Y %x %y} |
|
bind TkDND_Drag1 <B1-Motion> {tkdnd::_begin_drag motion 1 %W %s %X %Y %x %y} |
|
bind TkDND_Drag2 <ButtonPress-2> {tkdnd::_begin_drag press 2 %W %s %X %Y %x %y} |
|
bind TkDND_Drag2 <B2-Motion> {tkdnd::_begin_drag motion 2 %W %s %X %Y %x %y} |
|
bind TkDND_Drag3 <ButtonPress-3> {tkdnd::_begin_drag press 3 %W %s %X %Y %x %y} |
|
bind TkDND_Drag3 <B3-Motion> {tkdnd::_begin_drag motion 3 %W %s %X %Y %x %y} |
|
|
|
|
|
|
|
|
|
proc debug_enabled { {level {}} } { |
|
variable _debug_level |
|
if {$level != {}} { |
|
if {[string is integer -strict $level]} { |
|
set _debug_level $level |
|
} elseif {[string is true $level]} { |
|
set _debug_level 1 |
|
} |
|
} |
|
return $_debug_level |
|
} |
|
|
|
|
|
|
|
|
|
proc source { filename { encoding utf-8 } } { |
|
variable _package_dir |
|
|
|
set dbg_lvl [debug_enabled] |
|
if {$dbg_lvl} { |
|
puts "tkdnd::source (debug level $dbg_lvl) $filename" |
|
set fd [open $filename r] |
|
fconfigure $fd -encoding $encoding |
|
set script [read $fd] |
|
close $fd |
|
set map {} |
|
for {set lvl 0} {$lvl <= $dbg_lvl} {incr lvl} { |
|
lappend map "\#\D\B\G$lvl " {} |
|
} |
|
lappend map "\#\D\B\G\ " {} |
|
set script [string map $map $script] |
|
return [eval $script] |
|
} |
|
::source -encoding $encoding $filename |
|
} |
|
|
|
|
|
|
|
|
|
proc initialise { dir PKG_LIB_FILE PACKAGE_NAME} { |
|
variable _package_dir |
|
variable _platform_namespace |
|
variable _drop_file_temp_dir |
|
variable _windowingsystem |
|
global env |
|
|
|
set _package_dir $dir |
|
|
|
switch [tk windowingsystem] { |
|
x11 { |
|
set _windowingsystem x11 |
|
} |
|
win32 - |
|
windows { |
|
set _windowingsystem windows |
|
} |
|
aqua { |
|
set _windowingsystem aqua |
|
} |
|
default { |
|
error "unknown Tk windowing system" |
|
} |
|
} |
|
|
|
|
|
|
|
foreach var {HOME HOMEPATH USERPROFILE ALLUSERSPROFILE APPDATA} { |
|
if {[info exists env($var)]} { |
|
if {[file isdirectory $env($var)]} { |
|
set UserHomeDir $env($var) |
|
break |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
if {![info exists UserHomeDir] && |
|
[string equal $_windowingsystem windows] && |
|
[info exists env(HOMEDRIVE)] && [info exists env(HOMEPATH)]} { |
|
if {[file isdirectory $env(HOMEDRIVE)$env(HOMEPATH)]} { |
|
set UserHomeDir $env(HOMEDRIVE)$env(HOMEPATH) |
|
} |
|
} |
|
|
|
if {![info exists UserHomeDir]} { |
|
set UserHomeDir [pwd] |
|
} |
|
set UserHomeDir [file normalize $UserHomeDir] |
|
|
|
|
|
foreach var {TKDND_TEMP_DIR TEMP TMP} { |
|
if {[info exists env($var)]} { |
|
if {[file isdirectory $env($var)] && [file writable $env($var)]} { |
|
set _drop_file_temp_dir $env($var) |
|
break |
|
} |
|
} |
|
} |
|
if {![info exists _drop_file_temp_dir]} { |
|
foreach _dir [list "$UserHomeDir/Local Settings/Temp" \ |
|
"$UserHomeDir/AppData/Local/Temp" \ |
|
/tmp \ |
|
C:/WINDOWS/Temp C:/Temp C:/tmp \ |
|
D:/WINDOWS/Temp D:/Temp D:/tmp] { |
|
if {[file isdirectory $_dir] && [file writable $_dir]} { |
|
set _drop_file_temp_dir $_dir |
|
break |
|
} |
|
} |
|
} |
|
if {![info exists _drop_file_temp_dir]} { |
|
set _drop_file_temp_dir $UserHomeDir |
|
} |
|
set _drop_file_temp_dir [file native $_drop_file_temp_dir] |
|
|
|
source $dir/tkdnd_generic.tcl |
|
switch $_windowingsystem { |
|
x11 { |
|
source $dir/tkdnd_unix.tcl |
|
set _platform_namespace xdnd |
|
} |
|
win32 - |
|
windows { |
|
source $dir/tkdnd_windows.tcl |
|
set _platform_namespace olednd |
|
} |
|
aqua { |
|
source $dir/tkdnd_macosx.tcl |
|
set _platform_namespace macdnd |
|
} |
|
default { |
|
error "unknown Tk windowing system" |
|
} |
|
} |
|
load $dir/$PKG_LIB_FILE $PACKAGE_NAME |
|
source $dir/tkdnd_compat.tcl |
|
${_platform_namespace}::initialise |
|
} |
|
|
|
proc GetDropFileTempDirectory { } { |
|
variable _drop_file_temp_dir |
|
return $_drop_file_temp_dir |
|
} |
|
proc SetDropFileTempDirectory { dir } { |
|
variable _drop_file_temp_dir |
|
set _drop_file_temp_dir $dir |
|
} |
|
|
|
proc debug {msg} { |
|
puts $msg |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::drag_source { mode path { types {} } { event 1 } |
|
{ tagprefix TkDND_Drag } } { |
|
|
|
foreach single_event $event { |
|
set tags [bindtags $path] |
|
set idx [lsearch $tags ${tagprefix}$single_event] |
|
switch -- $mode { |
|
register { |
|
if { $idx != -1 } { |
|
|
|
|
|
} else { |
|
bindtags $path [linsert $tags 1 ${tagprefix}$single_event] |
|
} |
|
_drag_source_update_types $path $types |
|
} |
|
unregister { |
|
if { $idx != -1 } { |
|
bindtags $path [lreplace $tags $idx $idx] |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
proc ::tkdnd::_drag_source_update_types { path types } { |
|
set types [platform_specific_types $types] |
|
set old_types [bind $path <<DragSourceTypes>>] |
|
foreach type $types { |
|
if {[lsearch $old_types $type] < 0} {lappend old_types $type} |
|
} |
|
bind $path <<DragSourceTypes>> $old_types |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::drop_target { mode path { types {} } } { |
|
variable _windowingsystem |
|
set types [platform_specific_types $types] |
|
switch -- $mode { |
|
register { |
|
switch $_windowingsystem { |
|
x11 { |
|
_register_types $path [winfo toplevel $path] $types |
|
} |
|
win32 - |
|
windows { |
|
_RegisterDragDrop $path |
|
bind <Destroy> $path {+ tkdnd::_RevokeDragDrop %W} |
|
} |
|
aqua { |
|
macdnd::registerdragwidget [winfo toplevel $path] $types |
|
} |
|
default { |
|
error "unknown Tk windowing system" |
|
} |
|
} |
|
set old_types [bind $path <<DropTargetTypes>>] |
|
set new_types {} |
|
foreach type $types { |
|
if {[lsearch -exact $old_types $type] < 0} {lappend new_types $type} |
|
} |
|
if {[llength $new_types]} { |
|
bind $path <<DropTargetTypes>> [concat $old_types $new_types] |
|
} |
|
} |
|
unregister { |
|
switch $_windowingsystem { |
|
x11 { |
|
} |
|
win32 - |
|
windows { |
|
_RevokeDragDrop $path |
|
} |
|
aqua { |
|
error todo |
|
} |
|
default { |
|
error "unknown Tk windowing system" |
|
} |
|
} |
|
bind $path <<DropTargetTypes>> {} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::_begin_drag { event button source state X Y x y } { |
|
variable _x0 |
|
variable _y0 |
|
variable _state |
|
|
|
switch -- $event { |
|
press { |
|
set _x0 $X |
|
set _y0 $Y |
|
set _state "press" |
|
} |
|
motion { |
|
if { ![info exists _state] } { |
|
|
|
|
|
return |
|
} |
|
if { [string equal $_state "press"] } { |
|
variable _dx |
|
variable _dy |
|
if { abs($_x0-$X) > ${_dx} || abs($_y0-$Y) > ${_dy} } { |
|
set _state "done" |
|
_init_drag $button $source $state $X $Y $x $y |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::_init_drag { button source state rootX rootY X Y } { |
|
|
|
|
|
set cmd [bind $source <<DragInitCmd>>] |
|
|
|
if {[string length $cmd]} { |
|
set cmd [string map [list %W [list $source] \ |
|
%X $rootX %Y $rootY %x $X %y $Y \ |
|
%S $state %e <<DragInitCmd>> %A \{\} %% % \ |
|
%b \{$button\} \ |
|
%t \{[bind $source <<DragSourceTypes>>]\}] $cmd] |
|
set code [catch {uplevel \#0 $cmd} info options] |
|
|
|
switch -exact -- $code { |
|
0 {} |
|
3 - 4 { |
|
|
|
return |
|
} |
|
default { |
|
return -options $options $info |
|
} |
|
} |
|
|
|
set len [llength $info] |
|
if {$len == 3} { |
|
foreach { actions types _data } $info { break } |
|
set types [platform_specific_types $types] |
|
set data [list] |
|
foreach type $types { |
|
lappend data $_data |
|
} |
|
unset _data |
|
} elseif {$len == 2} { |
|
foreach { actions _data } $info { break } |
|
set data [list]; set types [list] |
|
foreach {t d} $_data { |
|
foreach t [platform_specific_types $t] { |
|
lappend types $t; lappend data $d |
|
} |
|
} |
|
unset _data t d |
|
} else { |
|
foreach { actions } $info { break } |
|
if {$len == 1 && [string equal [lindex $actions 0] "refuse_drop"]} { |
|
return |
|
} |
|
error "not enough items in the result of the <<DragInitCmd>>\ |
|
event binding. Either 2 or 3 items are expected. The command |
|
executed was: \"$cmd\"\nResult was: \"$info\"" |
|
} |
|
set action refuse_drop |
|
|
|
|
|
|
|
set cursor_map [bind $source <<DragCursorMap>>] |
|
|
|
variable _windowingsystem |
|
|
|
|
|
|
|
|
|
|
|
|
|
switch $_windowingsystem { |
|
x11 { |
|
set action [xdnd::_dodragdrop $source $actions $types $data $button $cursor_map] |
|
} |
|
win32 - |
|
windows { |
|
set action [_DoDragDrop $source $actions $types $data $button] |
|
} |
|
aqua { |
|
set action [macdnd::dodragdrop $source $actions $types $data $button] |
|
} |
|
default { |
|
error "unknown Tk windowing system" |
|
} |
|
} |
|
|
|
|
|
_end_drag $button $source {} $action {} $data {} $state $rootX $rootY $X $Y |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::_end_drag { button source target action type data result |
|
state rootX rootY X Y } { |
|
set rootX 0 |
|
set rootY 0 |
|
|
|
set cmd [bind $source <<DragEndCmd>>] |
|
if {[string length $cmd]} { |
|
set cmd [string map [list %W [list $source] \ |
|
%X $rootX %Y $rootY %x $X %y $Y %% % \ |
|
%b \{$button\} \ |
|
%S $state %e <<DragEndCmd>> %A \{$action\}] $cmd] |
|
set info [uplevel \#0 $cmd] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::platform_specific_types { types } { |
|
variable _platform_namespace |
|
${_platform_namespace}::platform_specific_types $types |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::platform_independent_types { types } { |
|
variable _platform_namespace |
|
${_platform_namespace}::platform_independent_types $types |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::platform_specific_type { type } { |
|
variable _platform_namespace |
|
${_platform_namespace}::platform_specific_type $type |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::platform_independent_type { type } { |
|
variable _platform_namespace |
|
${_platform_namespace}::platform_independent_type $type |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::bytes_to_string { bytes } { |
|
set string {} |
|
foreach byte $bytes { |
|
append string [binary format c $byte] |
|
} |
|
return $string |
|
} |
|
|
|
|
|
|
|
|
|
proc ::tkdnd::urn_unquote {url} { |
|
set result "" |
|
set start 0 |
|
while {[regexp -start $start -indices {%[0-9a-fA-F]{2}} $url match]} { |
|
foreach {first last} $match break |
|
append result [string range $url $start [expr {$first - 1}]] |
|
append result [format %c 0x[string range $url [incr first] $last]] |
|
set start [incr last] |
|
} |
|
append result [string range $url $start end] |
|
return [encoding convertfrom utf-8 $result] |
|
} |
|
|