diff options
Diffstat (limited to 'library/tkfbox.tcl')
-rw-r--r-- | library/tkfbox.tcl | 579 |
1 files changed, 367 insertions, 212 deletions
diff --git a/library/tkfbox.tcl b/library/tkfbox.tcl index bf6cf87..bbea5c6 100644 --- a/library/tkfbox.tcl +++ b/library/tkfbox.tcl @@ -17,11 +17,13 @@ # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # +package require Ttk + #---------------------------------------------------------------------- # # I C O N L I S T # -# This is a pseudo-widget that implements the icon list inside the +# This is a pseudo-widget that implements the icon list inside the # ::tk::dialog::file:: dialog box. # #---------------------------------------------------------------------- @@ -36,15 +38,16 @@ proc ::tk::IconList {w args} { } proc ::tk::IconList_Index {w i} { - upvar #0 ::tk::$w data - upvar #0 ::tk::$w:itemList itemList - if {![info exists data(list)]} {set data(list) {}} + upvar #0 ::tk::$w data ::tk::$w:itemList itemList + if {![info exists data(list)]} { + set data(list) {} + } switch -regexp -- $i { "^-?[0-9]+$" { - if { $i < 0 } { + if {$i < 0} { set i 0 } - if { $i >= [llength $data(list)] } { + if {$i >= [llength $data(list)]} { set i [expr {[llength $data(list)] - 1}] } return $i @@ -62,7 +65,8 @@ proc ::tk::IconList_Index {w i} { foreach {x y} [scan $i "@%d,%d"] { break } - set item [$data(canvas) find closest $x $y] + set item [$data(canvas) find closest \ + [$data(canvas) canvasx $x] [$data(canvas) canvasy $y]] return [lindex [$data(canvas) itemcget $item -tags] 1] } } @@ -72,18 +76,18 @@ proc ::tk::IconList_Selection {w op args} { upvar ::tk::$w data switch -exact -- $op { "anchor" { - if { [llength $args] == 1 } { + if {[llength $args] == 1} { set data(index,anchor) [tk::IconList_Index $w [lindex $args 0]] } else { return $data(index,anchor) } } "clear" { - if { [llength $args] == 2 } { + if {[llength $args] == 2} { foreach {first last} $args { break } - } elseif { [llength $args] == 1 } { + } elseif {[llength $args] == 1} { set first [set last [lindex $args 0]] } else { error "wrong # args: should be [lindex [info level 0] 0] path\ @@ -91,7 +95,7 @@ proc ::tk::IconList_Selection {w op args} { } set first [IconList_Index $w $first] set last [IconList_Index $w $last] - if { $first > $last } { + if {$first > $last} { set tmp $first set first $last set last $tmp @@ -102,6 +106,7 @@ proc ::tk::IconList_Selection {w op args} { set first $ind break } + incr ind } set ind [expr {[llength $data(selection)] - 1}] for {} {$ind >= 0} {incr ind -1} { @@ -152,7 +157,7 @@ proc ::tk::IconList_Selection {w op args} { } } -proc ::tk::IconList_Curselection {w} { +proc ::tk::IconList_CurSelection {w} { upvar ::tk::$w data return $data(selection) } @@ -162,6 +167,10 @@ proc ::tk::IconList_DrawSelection {w} { upvar ::tk::$w:itemList itemList $data(canvas) delete selection + $data(canvas) itemconfigure selectionText -fill black + $data(canvas) dtag selectionText + set cbg [ttk::style lookup TEntry -selectbackground focus] + set cfg [ttk::style lookup TEntry -selectforeground focus] foreach item $data(selection) { set rTag [lindex [lindex $data(list) $item] 2] foreach {iTag tTag text serial} $itemList($rTag) { @@ -169,8 +178,9 @@ proc ::tk::IconList_DrawSelection {w} { } set bbox [$data(canvas) bbox $tTag] - $data(canvas) create rect $bbox -fill \#a0a0ff -outline \#a0a0ff \ + $data(canvas) create rect $bbox -fill $cbg -outline $cbg \ -tags selection + $data(canvas) itemconfigure $tTag -fill $cfg -tags selectionText } $data(canvas) lower selection return @@ -214,13 +224,15 @@ proc ::tk::IconList_Config {w argList} { proc ::tk::IconList_Create {w} { upvar ::tk::$w data - frame $w - set data(sbar) [scrollbar $w.sbar -orient horizontal -takefocus 0] + ttk::frame $w + ttk::entry $w.cHull -takefocus 0 -cursor {} + set data(sbar) [ttk::scrollbar $w.cHull.sbar -orient horizontal -takefocus 0] catch {$data(sbar) configure -highlightthickness 0} - set data(canvas) [canvas $w.canvas -bd 2 -relief sunken \ - -width 400 -height 120 -takefocus 1] - pack $data(sbar) -side bottom -fill x -padx 2 - pack $data(canvas) -expand yes -fill both + set data(canvas) [canvas $w.cHull.canvas -highlightthick 0 \ + -width 400 -height 120 -takefocus 1 -background white] + pack $data(sbar) -side bottom -fill x -padx 2 -in $w.cHull -pady {0 2} + pack $data(canvas) -expand yes -fill both -padx 2 -pady {2 0} + pack $w.cHull -expand yes -fill both -ipadx 2 -ipady 2 $data(sbar) configure -command [list $data(canvas) xview] $data(canvas) configure -xscrollcommand [list $data(sbar) set] @@ -232,7 +244,6 @@ proc ::tk::IconList_Create {w} { set data(maxTW) 1 set data(maxTH) 1 set data(numItems) 0 - set data(curItem) {} set data(noScroll) 1 set data(selection) {} set data(index,anchor) "" @@ -257,6 +268,10 @@ proc ::tk::IconList_Create {w} { bind $data(canvas) <Double-ButtonRelease-1> \ [list tk::IconList_Double1 $w %x %y] + bind $data(canvas) <Control-B1-Motion> {;} + bind $data(canvas) <Shift-B1-Motion> \ + [list tk::IconList_ShiftMotion1 $w %x %y] + bind $data(canvas) <Up> [list tk::IconList_UpDown $w -1] bind $data(canvas) <Down> [list tk::IconList_UpDown $w 1] bind $data(canvas) <Left> [list tk::IconList_LeftRight $w -1] @@ -324,7 +339,6 @@ proc ::tk::IconList_DeleteAll {w} { set data(maxTW) 1 set data(maxTH) 1 set data(numItems) 0 - set data(curItem) {} set data(noScroll) 1 set data(selection) {} set data(index,anchor) "" @@ -347,7 +361,7 @@ proc ::tk::IconList_Add {w image items} { -tags [list text $data(numItems) item$data(numItems)]] set rTag [$data(canvas) create rect 0 0 0 0 -fill "" -outline "" \ -tags [list rect $data(numItems) item$data(numItems)]] - + foreach {x1 y1 x2 y2} [$data(canvas) bbox $iTag] { break } @@ -359,7 +373,7 @@ proc ::tk::IconList_Add {w image items} { if {$data(maxIH) < $iH} { set data(maxIH) $iH } - + foreach {x1 y1 x2 y2} [$data(canvas) bbox $tTag] { break } @@ -371,7 +385,7 @@ proc ::tk::IconList_Add {w image items} { if {$data(maxTH) < $tH} { set data(maxTH) $tH } - + lappend data(list) [list $iTag $tTag $rTag $iW $iH $tW \ $tH $data(numItems)] set itemList($rTag) [list $iTag $tTag $text $data(numItems)] @@ -459,9 +473,7 @@ proc ::tk::IconList_Arrange {w} { set data(itemsPerColumn) 1 } - if {$data(curItem) ne ""} { - IconList_Select $w [lindex [lindex $data(list) $data(curItem)] 2] 0 - } + IconList_DrawSelection $w } # Gets called when the user invokes the IconList (usually by double-clicking @@ -531,10 +543,10 @@ proc ::tk::IconList_Btn1 {w x y} { upvar ::tk::$w data focus $data(canvas) - set x [expr {int([$data(canvas) canvasx $x])}] - set y [expr {int([$data(canvas) canvasy $y])}] - set i [IconList_Index $w @${x},${y}] - if {$i eq ""} return + set i [IconList_Index $w @$x,$y] + if {$i eq ""} { + return + } IconList_Selection $w clear 0 end IconList_Selection $w set $i IconList_Selection $w anchor $i @@ -542,13 +554,13 @@ proc ::tk::IconList_Btn1 {w x y} { proc ::tk::IconList_CtrlBtn1 {w x y} { upvar ::tk::$w data - + if { $data(-multiple) } { focus $data(canvas) - set x [expr {int([$data(canvas) canvasx $x])}] - set y [expr {int([$data(canvas) canvasy $y])}] - set i [IconList_Index $w @${x},${y}] - if {$i eq ""} return + set i [IconList_Index $w @$x,$y] + if {$i eq ""} { + return + } if { [IconList_Selection $w includes $i] } { IconList_Selection $w clear $i } else { @@ -560,37 +572,48 @@ proc ::tk::IconList_CtrlBtn1 {w x y} { proc ::tk::IconList_ShiftBtn1 {w x y} { upvar ::tk::$w data - + if { $data(-multiple) } { focus $data(canvas) - set x [expr {int([$data(canvas) canvasx $x])}] - set y [expr {int([$data(canvas) canvasy $y])}] - set i [IconList_Index $w @${x},${y}] - if {$i eq ""} return - set a [IconList_Index $w anchor] - if { $a eq "" } { - set a $i + set i [IconList_Index $w @$x,$y] + if {$i eq ""} { + return + } + if {[IconList_Index $w anchor] eq ""} { + IconList_Selection $w anchor $i } IconList_Selection $w clear 0 end - IconList_Selection $w set $a $i + IconList_Selection $w set anchor $i } } # Gets called on button-1 motions # proc ::tk::IconList_Motion1 {w x y} { - upvar ::tk::$w data variable ::tk::Priv set Priv(x) $x set Priv(y) $y - set x [expr {int([$data(canvas) canvasx $x])}] - set y [expr {int([$data(canvas) canvasy $y])}] - set i [IconList_Index $w @${x},${y}] - if {$i eq ""} return + set i [IconList_Index $w @$x,$y] + if {$i eq ""} { + return + } IconList_Selection $w clear 0 end IconList_Selection $w set $i } +proc ::tk::IconList_ShiftMotion1 {w x y} { + upvar ::tk::$w data + variable ::tk::Priv + set Priv(x) $x + set Priv(y) $y + set i [IconList_Index $w @$x,$y] + if {$i eq ""} { + return + } + IconList_Selection $w clear 0 end + IconList_Selection $w set anchor $i +} + proc ::tk::IconList_Double1 {w x y} { upvar ::tk::$w data @@ -614,6 +637,7 @@ proc ::tk::IconList_Leave1 {w x y} { proc ::tk::IconList_FocusIn {w} { upvar ::tk::$w data + $w.cHull state focus if {![info exists data(list)]} { return } @@ -624,6 +648,7 @@ proc ::tk::IconList_FocusIn {w} { } proc ::tk::IconList_FocusOut {w} { + $w.cHull state !focus IconList_Selection $w clear 0 end } @@ -642,12 +667,14 @@ proc ::tk::IconList_UpDown {w amount} { return } - set curr [tk::IconList_Curselection $w] + set curr [tk::IconList_CurSelection $w] if { [llength $curr] == 0 } { set i 0 } else { set i [tk::IconList_Index $w anchor] - if {$i eq ""} return + if {$i eq ""} { + return + } incr i $amount } IconList_Selection $w clear 0 end @@ -671,12 +698,14 @@ proc ::tk::IconList_LeftRight {w amount} { return } - set curr [IconList_Curselection $w] + set curr [IconList_CurSelection $w] if { [llength $curr] == 0 } { set i 0 } else { set i [IconList_Index $w anchor] - if {$i eq ""} return + if {$i eq ""} { + return + } incr i [expr {$amount*$data(itemsPerColumn)}] } IconList_Selection $w clear 0 end @@ -716,24 +745,22 @@ proc ::tk::IconList_Goto {w text} { return } - if {$data(curItem) eq "" || $data(curItem) == 0} { - set start 0 + if {[llength [IconList_CurSelection $w]]} { + set start [IconList_Index $w anchor] } else { - set start $data(curItem) + set start 0 } - set text [string tolower $text] set theIndex -1 set less 0 set len [string length $text] set len0 [expr {$len-1}] set i $start - # Search forward until we find a filename whose prefix is an exact match - # with $text + # Search forward until we find a filename whose prefix is a + # case-insensitive match with $text while {1} { - set sub [string range $textList($i) 0 $len0] - if {$text eq $sub} { + if {[string equal -nocase -length $len0 $textList($i) $text]} { set theIndex $i break } @@ -789,34 +816,34 @@ proc ::tk::dialog::file:: {type args} { set dataName __tk_filedialog upvar ::tk::dialog::file::$dataName data - ::tk::dialog::file::Config $dataName $type $args + Config $dataName $type $args if {$data(-parent) eq "."} { - set w .$dataName + set w .$dataName } else { - set w $data(-parent).$dataName + set w $data(-parent).$dataName } # (re)create the dialog box if necessary # if {![winfo exists $w]} { - ::tk::dialog::file::Create $w TkFDialog + Create $w TkFDialog } elseif {[winfo class $w] ne "TkFDialog"} { destroy $w - ::tk::dialog::file::Create $w TkFDialog + Create $w TkFDialog } else { - set data(dirMenuBtn) $w.f1.menu - set data(dirMenu) $w.f1.menu.menu - set data(upBtn) $w.f1.up - set data(icons) $w.icons - set data(ent) $w.f2.ent - set data(typeMenuLab) $w.f2.lab2 - set data(typeMenuBtn) $w.f2.menu + set data(dirMenuBtn) $w.contents.f1.menu + set data(dirMenu) $w.contents.f1.menu.menu + set data(upBtn) $w.contents.f1.up + set data(icons) $w.contents.icons + set data(ent) $w.contents.f2.ent + set data(typeMenuLab) $w.contents.f2.lab2 + set data(typeMenuBtn) $w.contents.f2.menu set data(typeMenu) $data(typeMenuBtn).m - set data(okBtn) $w.f2.ok - set data(cancelBtn) $w.f2.cancel - set data(hiddenBtn) $w.f2.hidden - ::tk::dialog::file::SetSelectMode $w $data(-multiple) + set data(okBtn) $w.contents.f2.ok + set data(cancelBtn) $w.contents.f2.cancel + set data(hiddenBtn) $w.contents.f2.hidden + SetSelectMode $w $data(-multiple) } if {$::tk::dialog::file::showHiddenBtn} { $data(hiddenBtn) configure -state normal @@ -843,21 +870,39 @@ proc ::tk::dialog::file:: {type args} { # Add traces on the selectPath variable # - trace add variable data(selectPath) write [list ::tk::dialog::file::SetPath $w] + trace add variable data(selectPath) write \ + [list ::tk::dialog::file::SetPath $w] $data(dirMenuBtn) configure \ -textvariable ::tk::dialog::file::${dataName}(selectPath) + # Cleanup previous menu + # + $data(typeMenu) delete 0 end + $data(typeMenuBtn) configure -state normal -text "" + # Initialize the file types menu # if {[llength $data(-filetypes)]} { - $data(typeMenu) delete 0 end + # Default type and name to first entry + set initialtype [lindex $data(-filetypes) 0] + set initialTypeName [lindex $initialtype 0] + if {$data(-typevariable) ne ""} { + upvar #0 $data(-typevariable) typeVariable + if {[info exists typeVariable]} { + set initialTypeName $typeVariable + } + } foreach type $data(-filetypes) { set title [lindex $type 0] set filter [lindex $type 1] $data(typeMenu) add command -label $title \ -command [list ::tk::dialog::file::SetFilter $w $type] + # string first avoids glob-pattern char issues + if {[string first ${initialTypeName} $title] == 0} { + set initialtype $type + } } - ::tk::dialog::file::SetFilter $w [lindex $data(-filetypes) 0] + SetFilter $w $initialtype $data(typeMenuBtn) configure -state normal $data(typeMenuLab) configure -state normal } else { @@ -865,7 +910,7 @@ proc ::tk::dialog::file:: {type args} { $data(typeMenuBtn) configure -state disabled -takefocus 0 $data(typeMenuLab) configure -state disabled } - ::tk::dialog::file::UpdateWhenIdle $w + UpdateWhenIdle $w # Withdraw the window, then update all the geometry information # so we know how big it wants to be, then center the window in the @@ -929,14 +974,21 @@ proc ::tk::dialog::file::Config {dataName type argList} { {-initialfile "" "" ""} {-parent "" "" "."} {-title "" "" ""} + {-typevariable "" "" ""} } # The "-multiple" option is only available for the "open" file dialog. # - if { $type eq "open" } { + if {$type eq "open"} { lappend specs {-multiple "" "" "0"} } + # The "-confirmoverwrite" option is only for the "save" file dialog. + # + if {$type eq "save"} { + lappend specs {-confirmoverwrite "" "" "1"} + } + # 2: default values depending on the type of the dialog # if {![info exists data(selectPath)]} { @@ -951,9 +1003,9 @@ proc ::tk::dialog::file::Config {dataName type argList} { if {$data(-title) eq ""} { if {$type eq "open"} { - set data(-title) "[mc "Open"]" + set data(-title) [mc "Open"] } else { - set data(-title) "[mc "Save As"]" + set data(-title) [mc "Save As"] } } @@ -985,8 +1037,8 @@ proc ::tk::dialog::file::Config {dataName type argList} { # like "yes") so we can use it in tests more easily. if {$type eq "save"} { set data(-multiple) 0 - } elseif {$data(-multiple)} { - set data(-multiple) 1 + } elseif {$data(-multiple)} { + set data(-multiple) 1 } else { set data(-multiple) 0 } @@ -1000,16 +1052,25 @@ proc ::tk::dialog::file::Create {w class} { toplevel $w -class $class if {[tk windowingsystem] eq "x11"} {wm attributes $w -type dialog} + pack [ttk::frame $w.contents] -expand 1 -fill both + #set w $w.contents # f1: the frame with the directory option menu # - set f1 [frame $w.f1] - bind [::tk::AmpWidget label $f1.lab -text "[mc "&Directory:"]" ] \ - <<AltUnderlined>> [list focus $f1.menu] - + set f1 [ttk::frame $w.contents.f1] + bind [::tk::AmpWidget ttk::label $f1.lab -text [mc "&Directory:"]] \ + <<AltUnderlined>> [list focus $f1.menu] + set data(dirMenuBtn) $f1.menu - set data(dirMenu) [tk_optionMenu $f1.menu [format %s(selectPath) ::tk::dialog::file::$dataName] ""] - set data(upBtn) [button $f1.up] + if {![info exists data(selectPath)]} { + set data(selectPath) "" + } + set data(dirMenu) $f1.menu.menu + ttk::menubutton $f1.menu -menu $data(dirMenu) -direction flush \ + -textvariable [format %s(selectPath) ::tk::dialog::file::$dataName] + [menu $data(dirMenu) -tearoff 0] add radiobutton -label "" -variable \ + [format %s(selectPath) ::tk::dialog::file::$dataName] + set data(upBtn) [ttk::button $f1.up] if {![info exists Priv(updirImage)]} { set Priv(updirImage) [image create bitmap -data { #define updir_width 28 @@ -1024,7 +1085,7 @@ static char updir_bits[] = { } $data(upBtn) configure -image $Priv(updirImage) - $f1.menu configure -takefocus 1 -highlightthickness 2 + $f1.menu configure -takefocus 1;# -highlightthickness 2 pack $data(upBtn) -side right -padx 4 -fill both pack $f1.lab -side left -padx 4 -fill both @@ -1032,7 +1093,7 @@ static char updir_bits[] = { # data(icons): the IconList that list the files and directories. # - if { $class eq "TkFDialog" } { + if {$class eq "TkFDialog"} { if { $data(-multiple) } { set fNameCaption [mc "File &names:"] } else { @@ -1044,34 +1105,35 @@ static char updir_bits[] = { set fNameCaption [mc "&Selection:"] set iconListCommand [list ::tk::dialog::file::chooseDir::DblClick $w] } - set data(icons) [::tk::IconList $w.icons \ - -command $iconListCommand \ - -multiple $data(-multiple)] + set data(icons) [::tk::IconList $w.contents.icons \ + -command $iconListCommand -multiple $data(-multiple)] bind $data(icons) <<ListboxSelect>> \ [list ::tk::dialog::file::ListBrowse $w] # f2: the frame with the OK button, cancel button, "file name" field # and file types field. # - set f2 [frame $w.f2 -bd 0] - bind [::tk::AmpWidget label $f2.lab -text $fNameCaption -anchor e -pady 0]\ + set f2 [ttk::frame $w.contents.f2] + bind [::tk::AmpWidget ttk::label $f2.lab -text $fNameCaption -anchor e]\ <<AltUnderlined>> [list focus $f2.ent] - set data(ent) [entry $f2.ent] + # -pady 0 + set data(ent) [ttk::entry $f2.ent] # The font to use for the icons. The default Canvas font on Unix # is just deviant. - set ::tk::$w.icons(font) [$data(ent) cget -font] + set ::tk::$w.contents.icons(font) [$data(ent) cget -font] # Make the file types bits only if this is a File Dialog - if { $class eq "TkFDialog" } { - set data(typeMenuLab) [::tk::AmpWidget label $f2.lab2 \ - -text $fTypeCaption -anchor e -pady [$f2.lab cget -pady]] - set data(typeMenuBtn) [menubutton $f2.menu -indicatoron 1 \ + if {$class eq "TkFDialog"} { + set data(typeMenuLab) [::tk::AmpWidget ttk::label $f2.lab2 \ + -text $fTypeCaption -anchor e] + # -pady [$f2.lab cget -pady] + set data(typeMenuBtn) [ttk::menubutton $f2.menu \ -menu $f2.menu.m] + # -indicatoron 1 set data(typeMenu) [menu $data(typeMenuBtn).m -tearoff 0] - $data(typeMenuBtn) configure -takefocus 1 -highlightthickness 2 \ - -relief raised -bd 2 -anchor w - bind $data(typeMenuLab) <<AltUnderlined>> [list \ + # $data(typeMenuBtn) configure -takefocus 1 -relief raised -anchor w + bind $data(typeMenuLab) <<AltUnderlined>> [list \ focus $data(typeMenuBtn)] } @@ -1083,10 +1145,11 @@ static char updir_bits[] = { } else { set text [mc "Show &Hidden Directories"] } - set data(hiddenBtn) [::tk::AmpWidget checkbutton $f2.hidden \ - -text $text -anchor w -padx 3 -state disabled \ + set data(hiddenBtn) [::tk::AmpWidget ttk::checkbutton $f2.hidden \ + -text $text -state disabled \ -variable ::tk::dialog::file::showHiddenVar \ -command [list ::tk::dialog::file::UpdateWhenIdle $w]] +# -anchor w -padx 3 # the okBtn is created after the typeMenu so that the keyboard traversal # is in the right order, and add binding so that we find out when the @@ -1094,17 +1157,17 @@ static char updir_bits[] = { # window so no confusion about how much <Destroy> gets called; exactly # once will do). [Bug 987169] - set data(okBtn) [::tk::AmpWidget button $f2.ok \ - -text [mc "&OK"] -default active -pady 3] + set data(okBtn) [::tk::AmpWidget ttk::button $f2.ok \ + -text [mc "&OK"] -default active];# -pady 3] bind $data(okBtn) <Destroy> [list ::tk::dialog::file::Destroyed $w] - set data(cancelBtn) [::tk::AmpWidget button $f2.cancel \ - -text [mc "&Cancel"] -default normal -pady 3] + set data(cancelBtn) [::tk::AmpWidget ttk::button $f2.cancel \ + -text [mc "&Cancel"] -default normal];# -pady 3] # grid the widgets in f2 # - grid $f2.lab $f2.ent $data(okBtn) -padx 4 -sticky ew + grid $f2.lab $f2.ent $data(okBtn) -padx 4 -pady 3 -sticky ew grid configure $f2.ent -padx 2 - if { $class eq "TkFDialog" } { + if {$class eq "TkFDialog"} { grid $data(typeMenuLab) $data(typeMenuBtn) $data(cancelBtn) \ -padx 4 -sticky ew grid configure $data(typeMenuBtn) -padx 0 @@ -1117,7 +1180,7 @@ static char updir_bits[] = { # Pack all the frames together. We are done with widget construction. # pack $f1 -side top -fill x -pady 4 - pack $f2 -side bottom -fill x + pack $f2 -side bottom -pady 4 -fill x pack $data(icons) -expand yes -fill both -padx 4 -pady 1 # Set up the event handlers that are common to Directory and File Dialogs @@ -1126,12 +1189,12 @@ static char updir_bits[] = { wm protocol $w WM_DELETE_WINDOW [list ::tk::dialog::file::CancelCmd $w] $data(upBtn) configure -command [list ::tk::dialog::file::UpDirCmd $w] $data(cancelBtn) configure -command [list ::tk::dialog::file::CancelCmd $w] - bind $w <KeyPress-Escape> [list tk::ButtonInvoke $data(cancelBtn)] + bind $w <KeyPress-Escape> [list $data(cancelBtn) invoke] bind $w <Alt-Key> [list tk::AltKeyInDialog $w %A] # Set up event handlers specific to File or Directory Dialogs # - if { $class eq "TkFDialog" } { + if {$class eq "TkFDialog"} { bind $data(ent) <Return> [list ::tk::dialog::file::ActivateEnt $w] $data(okBtn) configure -command [list ::tk::dialog::file::OkCmd $w] bind $w <Alt-t> [format { @@ -1144,15 +1207,18 @@ static char updir_bits[] = { bind $data(ent) <Return> $okCmd $data(okBtn) configure -command $okCmd bind $w <Alt-s> [list focus $data(ent)] - bind $w <Alt-o> [list tk::ButtonInvoke $data(okBtn)] + bind $w <Alt-o> [list $data(okBtn) invoke] } bind $w <Alt-h> [list $data(hiddenBtn) invoke] + bind $data(ent) <Tab> [list ::tk::dialog::file::CompleteEnt $w] # Build the focus group for all the entries # ::tk::FocusGroup_Create $w - ::tk::FocusGroup_BindIn $w $data(ent) [list ::tk::dialog::file::EntFocusIn $w] - ::tk::FocusGroup_BindOut $w $data(ent) [list ::tk::dialog::file::EntFocusOut $w] + ::tk::FocusGroup_BindIn $w $data(ent) [list \ + ::tk::dialog::file::EntFocusIn $w] + ::tk::FocusGroup_BindOut $w $data(ent) [list \ + ::tk::dialog::file::EntFocusOut $w] } # ::tk::dialog::file::SetSelectMode -- @@ -1170,12 +1236,12 @@ proc ::tk::dialog::file::SetSelectMode {w multi} { set dataName __tk_filedialog upvar ::tk::dialog::file::$dataName data if { $multi } { - set fNameCaption "[mc {File &names:}]" + set fNameCaption [mc "File &names:"] } else { - set fNameCaption "[mc {File &name:}]" + set fNameCaption [mc "File &name:"] } set iconListCommand [list ::tk::dialog::file::OkCmd $w] - ::tk::SetAmpText $w.f2.lab $fNameCaption + ::tk::SetAmpText $w.contents.f2.lab $fNameCaption ::tk::IconList_Config $data(icons) \ [list -multiple $multi -command $iconListCommand] return @@ -1242,7 +1308,7 @@ rSASvJTGhnhcV3EJlo3kh53ltF5nAhQAOw==}] # we normally won't come to here. Anyways, give an error and abort # action. tk_messageBox -type ok -parent $w -icon warning -message \ - [mc "Cannot change to the directory \"%1\$s\".\nPermission denied." $data(selectPath)] + [mc "Cannot change to the directory \"%1\$s\".\nPermission denied." $data(selectPath)] cd $appPWD return } @@ -1279,10 +1345,12 @@ rSASvJTGhnhcV3EJlo3kh53ltF5nAhQAOw==}] # but 'd'irectory type files. # set cmd [list glob -tails -directory [pwd] \ - -type {f b c l p s} -nocomplain] + -type {f b c l p s} -nocomplain] if {$data(filter) eq "*"} { lappend cmd * - if {$showHidden} { lappend cmd .* } + if {$showHidden} { + lappend cmd .* + } } else { eval [list lappend cmd] $data(filter) } @@ -1311,7 +1379,7 @@ rSASvJTGhnhcV3EJlo3kh53ltF5nAhQAOw==}] # cd $appPWD - if { $class eq "TkFDialog" } { + if {$class eq "TkFDialog"} { # Restore the Open/Save Button if this is a File Dialog # if {$data(type) eq "open"} { @@ -1333,7 +1401,7 @@ rSASvJTGhnhcV3EJlo3kh53ltF5nAhQAOw==}] # proc ::tk::dialog::file::SetPathSilently {w path} { upvar ::tk::dialog::file::[winfo name $w] data - + trace remove variable data(selectPath) write [list ::tk::dialog::file::SetPath $w] set data(selectPath) $path trace add variable data(selectPath) write [list ::tk::dialog::file::SetPath $w] @@ -1345,9 +1413,9 @@ proc ::tk::dialog::file::SetPathSilently {w path} { proc ::tk::dialog::file::SetPath {w name1 name2 op} { if {[winfo exists $w]} { upvar ::tk::dialog::file::[winfo name $w] data - ::tk::dialog::file::UpdateWhenIdle $w + UpdateWhenIdle $w # On directory dialogs, we keep the entry in sync with the currentdir. - if { [winfo class $w] eq "TkChooseDir" } { + if {[winfo class $w] eq "TkChooseDir"} { $data(ent) delete 0 end $data(ent) insert end $data(selectPath) } @@ -1360,8 +1428,9 @@ proc ::tk::dialog::file::SetFilter {w type} { upvar ::tk::dialog::file::[winfo name $w] data upvar ::tk::$data(icons) icons + set data(filterType) $type set data(filter) [lindex $type 1] - $data(typeMenuBtn) configure -text [lindex $type 0] -indicatoron 1 + $data(typeMenuBtn) configure -text [lindex $type 0] ;#-indicatoron 1 # If we aren't using a default extension, use the one suppled # by the filter. @@ -1387,8 +1456,8 @@ proc ::tk::dialog::file::SetFilter {w type} { } $icons(sbar) set 0.0 0.0 - - ::tk::dialog::file::UpdateWhenIdle $w + + UpdateWhenIdle $w } # tk::dialog::file::ResolveFile -- @@ -1400,11 +1469,14 @@ proc ::tk::dialog::file::SetFilter {w type} { # (2) resolve all instances of . and .. # (3) check for non-existent files/directories # (4) check for chdir permissions +# (5) conversion of environment variable references to their +# contents (once only) # # Arguments: # context: the current directory you are in # text: the text entered by the user # defaultext: the default extension to add to files with no extension +# expandEnv: whether to expand environment variables (yes by default) # # Return vaue: # [list $flag $directory $file] @@ -1423,20 +1495,21 @@ proc ::tk::dialog::file::SetFilter {w type} { # directory may not be the same as context, because text may contain # a subdirectory name # -proc ::tk::dialog::file::ResolveFile {context text defaultext} { - +proc ::tk::dialog::file::ResolveFile {context text defaultext {expandEnv 1}} { set appPWD [pwd] - set path [::tk::dialog::file::JoinFile $context $text] + set path [JoinFile $context $text] # If the file has no extension, append the default. Be careful not # to do this for directories, otherwise typing a dirname in the box # will give back "dirname.extension" instead of trying to change dir. - if {![file isdirectory $path] && [file ext $path] eq ""} { + if { + ![file isdirectory $path] && ([file ext $path] eq "") && + ![string match {$*} [file tail $path]] + } then { set path "$path$defaultext" } - if {[catch {file exists $path}]} { # This "if" block can be safely removed if the following code # stop generating errors. @@ -1471,17 +1544,31 @@ proc ::tk::dialog::file::ResolveFile {context text defaultext} { return [list CHDIR $dirname ""] } set directory [pwd] + cd $appPWD set file [file tail $path] - if {[regexp {[*]|[?]} $file]} { + # It's nothing else, so check to see if it is an env-reference + if {$expandEnv && [string match {$*} $file]} { + set var [string range $file 1 end] + if {[info exist ::env($var)]} { + return [ResolveFile $context $::env($var) $defaultext 0] + } + } + if {[regexp {[*?]} $file]} { set flag PATTERN } else { set flag FILE } - cd $appPWD } else { set directory $dirname set file [file tail $path] set flag PATH + # It's nothing else, so check to see if it is an env-reference + if {$expandEnv && [string match {$*} $file]} { + set var [string range $file 1 end] + if {[info exist ::env($var)]} { + return [ResolveFile $context $::env($var) $defaultext 0] + } + } } } @@ -1490,7 +1577,7 @@ proc ::tk::dialog::file::ResolveFile {context text defaultext} { # Gets called when the entry box gets keyboard focus. We clear the selection -# from the icon list . This way the user can be certain that the input in the +# from the icon list . This way the user can be certain that the input in the # entry box is the selection. # proc ::tk::dialog::file::EntFocusIn {w} { @@ -1503,7 +1590,7 @@ proc ::tk::dialog::file::EntFocusIn {w} { $data(ent) selection clear } - if { [winfo class $w] eq "TkFDialog" } { + if {[winfo class $w] eq "TkFDialog"} { # If this is a File Dialog, make sure the buttons are labeled right. if {$data(type) eq "open"} { ::tk::SetAmpText $data(okBtn) [mc "&Open"] @@ -1527,24 +1614,11 @@ proc ::tk::dialog::file::ActivateEnt {w} { set text [$data(ent) get] if {$data(-multiple)} { - # For the multiple case we have to be careful to get the file - # names as a true list, watching out for a single file with a - # space in the name. Thus we query the IconList directly. - - set selIcos [::tk::IconList_Curselection $data(icons)] - set data(selectFile) "" - if {[llength $selIcos] == 0 && $text ne ""} { - # This assumes the user typed something in without selecting - # files - so assume they only type in a single filename. - ::tk::dialog::file::VerifyFileName $w $text - } else { - foreach item $selIcos { - ::tk::dialog::file::VerifyFileName $w \ - [::tk::IconList_Get $data(icons) $item] - } + foreach t $text { + VerifyFileName $w $t } } else { - ::tk::dialog::file::VerifyFileName $w $text + VerifyFileName $w $text } } @@ -1553,8 +1627,7 @@ proc ::tk::dialog::file::ActivateEnt {w} { proc ::tk::dialog::file::VerifyFileName {w filename} { upvar ::tk::dialog::file::[winfo name $w] data - set list [::tk::dialog::file::ResolveFile $data(selectPath) $filename \ - $data(-defaultextension)] + set list [ResolveFile $data(selectPath) $filename $data(-defaultextension)] foreach {flag path file} $list { break } @@ -1566,13 +1639,13 @@ proc ::tk::dialog::file::VerifyFileName {w filename} { set data(selectPath) $path $data(ent) delete 0 end } else { - ::tk::dialog::file::SetPathSilently $w $path + SetPathSilently $w $path if {$data(-multiple)} { lappend data(selectFile) $file } else { set data(selectFile) $file } - ::tk::dialog::file::Done $w + Done $w } } PATTERN { @@ -1582,36 +1655,36 @@ proc ::tk::dialog::file::VerifyFileName {w filename} { FILE { if {$data(type) eq "open"} { tk_messageBox -icon warning -type ok -parent $w \ - -message "[mc "File \"%1\$s\" does not exist." [file join $path $file]]" + -message [mc "File \"%1\$s\" does not exist." \ + [file join $path $file]] $data(ent) selection range 0 end $data(ent) icursor end } else { - ::tk::dialog::file::SetPathSilently $w $path + SetPathSilently $w $path if {$data(-multiple)} { lappend data(selectFile) $file } else { set data(selectFile) $file } - ::tk::dialog::file::Done $w + Done $w } } PATH { tk_messageBox -icon warning -type ok -parent $w \ - -message "[mc "Directory \"%1\$s\" does not exist." $path]" + -message [mc "Directory \"%1\$s\" does not exist." $path] $data(ent) selection range 0 end $data(ent) icursor end } CHDIR { - tk_messageBox -type ok -parent $w -message \ - "[mc "Cannot change to the directory \"%1\$s\".\nPermission denied." $path]"\ - -icon warning + tk_messageBox -type ok -parent $w -icon warning -message \ + [mc "Cannot change to the directory\ + \"%1\$s\".\nPermission denied." $path] $data(ent) selection range 0 end $data(ent) icursor end } ERROR { - tk_messageBox -type ok -parent $w -message \ - "[mc "Invalid file name \"%1\$s\"." $path]"\ - -icon warning + tk_messageBox -type ok -parent $w -icon warning -message \ + [mc "Invalid file name \"%1\$s\"." $path] $data(ent) selection range 0 end $data(ent) icursor end } @@ -1624,7 +1697,7 @@ proc ::tk::dialog::file::InvokeBtn {w key} { upvar ::tk::dialog::file::[winfo name $w] data if {[$data(okBtn) cget -text] eq $key} { - ::tk::ButtonInvoke $data(okBtn) + $data(okBtn) invoke } } @@ -1655,21 +1728,21 @@ proc ::tk::dialog::file::OkCmd {w} { upvar ::tk::dialog::file::[winfo name $w] data set filenames {} - foreach item [::tk::IconList_Curselection $data(icons)] { + foreach item [::tk::IconList_CurSelection $data(icons)] { lappend filenames [::tk::IconList_Get $data(icons) $item] } if {([llength $filenames] && !$data(-multiple)) || \ ($data(-multiple) && ([llength $filenames] == 1))} { set filename [lindex $filenames 0] - set file [::tk::dialog::file::JoinFile $data(selectPath) $filename] + set file [JoinFile $data(selectPath) $filename] if {[file isdirectory $file]} { - ::tk::dialog::file::ListInvoke $w [list $filename] + ListInvoke $w [list $filename] return } } - ::tk::dialog::file::ActivateEnt $w + ActivateEnt $w } # Gets called when user presses the "Cancel" button @@ -1698,16 +1771,16 @@ proc ::tk::dialog::file::ListBrowse {w} { upvar ::tk::dialog::file::[winfo name $w] data set text {} - foreach item [::tk::IconList_Curselection $data(icons)] { + foreach item [::tk::IconList_CurSelection $data(icons)] { lappend text [::tk::IconList_Get $data(icons) $item] } if {[llength $text] == 0} { return } - if { [llength $text] > 1 } { + if {$data(-multiple)} { set newtext {} foreach file $text { - set fullfile [::tk::dialog::file::JoinFile $data(selectPath) $file] + set fullfile [JoinFile $data(selectPath) $file] if { ![file isdirectory $fullfile] } { lappend newtext $file } @@ -1716,28 +1789,26 @@ proc ::tk::dialog::file::ListBrowse {w} { set isDir 0 } else { set text [lindex $text 0] - set file [::tk::dialog::file::JoinFile $data(selectPath) $text] + set file [JoinFile $data(selectPath) $text] set isDir [file isdirectory $file] } if {!$isDir} { $data(ent) delete 0 end $data(ent) insert 0 $text - if { [winfo class $w] eq "TkFDialog" } { + if {[winfo class $w] eq "TkFDialog"} { if {$data(type) eq "open"} { ::tk::SetAmpText $data(okBtn) [mc "&Open"] } else { ::tk::SetAmpText $data(okBtn) [mc "&Save"] } } - } else { - if { [winfo class $w] eq "TkFDialog" } { - ::tk::SetAmpText $data(okBtn) [mc "&Open"] - } + } elseif {[winfo class $w] eq "TkFDialog"} { + ::tk::SetAmpText $data(okBtn) [mc "&Open"] } } -# Gets called when user invokes the IconList widget (double-click, +# Gets called when user invokes the IconList widget (double-click, # Return key, etc) # proc ::tk::dialog::file::ListInvoke {w filenames} { @@ -1747,16 +1818,14 @@ proc ::tk::dialog::file::ListInvoke {w filenames} { return } - set file [::tk::dialog::file::JoinFile $data(selectPath) \ - [lindex $filenames 0]] - + set file [JoinFile $data(selectPath) [lindex $filenames 0]] + set class [winfo class $w] if {$class eq "TkChooseDir" || [file isdirectory $file]} { set appPWD [pwd] if {[catch {cd $file}]} { - tk_messageBox -type ok -parent $w -message \ - "[mc "Cannot change to the directory \"%1\$s\".\nPermission denied." $file]"\ - -icon warning + tk_messageBox -type ok -parent $w -icon warning -message \ + [mc "Cannot change to the directory \"%1\$s\".\nPermission denied." $file] } else { cd $appPWD set data(selectPath) $file @@ -1767,7 +1836,7 @@ proc ::tk::dialog::file::ListInvoke {w filenames} { } else { set data(selectFile) $file } - ::tk::dialog::file::Done $w + Done $w } } @@ -1787,28 +1856,114 @@ proc ::tk::dialog::file::Done {w {selectFilePath ""}} { if {$data(-multiple)} { set selectFilePath {} foreach f $data(selectFile) { - lappend selectFilePath [::tk::dialog::file::JoinFile \ - $data(selectPath) $f] + lappend selectFilePath [JoinFile $data(selectPath) $f] } } else { - set selectFilePath [::tk::dialog::file::JoinFile \ - $data(selectPath) $data(selectFile)] - } - - set Priv(selectFile) $data(selectFile) - set Priv(selectPath) $data(selectPath) - - if {$data(type) eq "save"} { - if {[file exists $selectFilePath]} { - set reply [tk_messageBox -icon warning -type yesno\ - -parent $w -message \ - "[mc "File \"%1\$s\" already exists.\nDo you want to overwrite it?" $selectFilePath]"] + set selectFilePath [JoinFile $data(selectPath) $data(selectFile)] + } + + set Priv(selectFile) $data(selectFile) + set Priv(selectPath) $data(selectPath) + + if {($data(type) eq "save") && $data(-confirmoverwrite) && [file exists $selectFilePath]} { + set reply [tk_messageBox -icon warning -type yesno -parent $w \ + -message [mc "File \"%1\$s\" already exists.\nDo you want\ + to overwrite it?" $selectFilePath]] if {$reply eq "no"} { return - } } } + if {[info exists data(-typevariable)] && $data(-typevariable) ne "" + && [info exists data(-filetypes)] && [llength $data(-filetypes)] + && [info exists data(filterType)] && $data(filterType) ne ""} { + upvar #0 $data(-typevariable) typeVariable + set typeVariable [lindex $data(filterType) 0] + } } bind $data(okBtn) <Destroy> {} set Priv(selectFilePath) $selectFilePath } + +proc ::tk::dialog::file::CompleteEnt {w} { + upvar ::tk::dialog::file::[winfo name $w] data + set f [$data(ent) get] + if {$data(-multiple)} { + if {[catch {llength $f} len] || $len != 1} { + return -code break + } + set f [lindex $f 0] + } + + # Get list of matching filenames and dirnames + set globF [list glob -tails -directory $data(selectPath) \ + -type {f b c l p s} -nocomplain] + set globD [list glob -tails -directory $data(selectPath) -type d \ + -nocomplain *] + if {$data(filter) eq "*"} { + lappend globF * + if {$::tk::dialog::file::showHiddenVar} { + lappend globF .* + lappend globD .* + } + if {[winfo class $w] eq "TkFDialog"} { + set files [lsort -dictionary -unique [{*}$globF]] + } else { + set files {} + } + set dirs [lsort -dictionary -unique [{*}$globD]] + } else { + if {$::tk::dialog::file::showHiddenVar} { + lappend globD .* + } + if {[winfo class $w] eq "TkFDialog"} { + set files [lsort -dictionary -unique [{*}$globF {*}$data(filter)]] + } else { + set files {} + } + set dirs [lsort -dictionary -unique [{*}$globD]] + } + # Filter specials + set dirs [lsearch -all -not -exact -inline $dirs .] + set dirs [lsearch -all -not -exact -inline $dirs ..] + set dirs2 {} + foreach d $dirs {lappend dirs2 $d/} + + set targets [concat \ + [lsearch -glob -all -inline $files $f*] \ + [lsearch -glob -all -inline $dirs2 $f*]] + + if {[llength $targets] == 1} { + # We have a winner! + set f [lindex $targets 0] + } elseif {$f in $targets || [llength $targets] == 0} { + if {[string length $f] > 0} { + bell + } + return + } elseif {[llength $targets] > 1} { + # Multiple possibles + if {[string length $f] == 0} { + return + } + set t0 [lindex $targets 0] + for {set len [string length $t0]} {$len>0} {} { + set allmatch 1 + foreach s $targets { + if {![string equal -length $len $s $t0]} { + set allmatch 0 + break + } + } + incr len -1 + if {$allmatch} break + } + set f [string range $t0 0 $len] + } + + if {$data(-multiple)} { + set f [list $f] + } + $data(ent) delete 0 end + $data(ent) insert 0 $f + return -code break +} |