pure-data/tcl/dialog_path.tcl


package provide dialog_path 0.1

package require scrollboxwindow

namespace eval ::dialog_path:: {
    variable use_standard_paths_button 1
    variable verbose_button 0
    variable docspath ""
    variable installpath ""
    namespace export pdtk_path_dialog
}

############ pdtk_path_dialog -- run a path dialog #########

proc ::dialog_path::cancel {mytoplevel} {
    ::scrollboxwindow::cancel $mytoplevel
}

proc ::dialog_path::ok {mytoplevel} {
    ::scrollboxwindow::ok $mytoplevel dialog_path::commit
}

# set up the panel with the info from pd
proc ::dialog_path::pdtk_path_dialog {mytoplevel extrapath verbose} {
    set ::sys_use_stdpath $extrapath
    set ::sys_verbose $verbose
    if {[winfo exists $mytoplevel]} {
        # this doesn't seem to be called...
        wm deiconify $mytoplevel
        raise $mytoplevel
        focus $mytoplevel
    } else {
        create_dialog $mytoplevel
    }
}


proc ::dialog_path::fill_frame {frame {with_verbose 0}} {
    # 'frame' is a frame, rather than a toplevel window
    set readonly_color [lindex [$frame configure -background] end]

    if {[namespace exists ::deken]} {set ::dialog_path::installpath $::deken::installpath}

    # scrollbox
    ::scrollbox::make ${frame} $::sys_searchpath \
        ::dialog_path::add dialog_path::edit \
        [_ "Pd search path for objects, help, audio, text and other files"]

    # path options
    frame $frame.extraframe
    pack $frame.extraframe -side top -anchor s -fill x
    checkbutton $frame.extraframe.extra -text [_ "Use standard paths"] \
        -variable ::sys_use_stdpath -anchor w
    pack $frame.extraframe.extra -side left -expand 1
    if { ${with_verbose} ne 0 } {
        checkbutton $frame.extraframe.verbose -text [_ "Verbose"] \
            -variable ::sys_verbose -anchor w
        pack $frame.extraframe.verbose -side right -expand 1
    }

    # add docsdir path widgets if pd_docsdir is loaded
    if {[namespace exists ::pd_docsdir]} {
        set ::dialog_path::docspath $::pd_docsdir::docspath
        labelframe $frame.docspath -text [_ "Pd Documents Directory"] \
            -borderwidth 1 -padx 5 -pady 5
        pack $frame.docspath -side top -anchor s -fill x -padx {2m 4m} -pady 2m

        frame $frame.docspath.path
        pack $frame.docspath.path -fill x
        entry $frame.docspath.path.entry -textvariable ::dialog_path::docspath \
            -takefocus 0 -state readonly -readonlybackground $readonly_color
        button $frame.docspath.path.browse -text [_ "Browse"] \
            -command "::dialog_path::browse_docspath $frame"
        pack $frame.docspath.path.browse -side right -fill x -ipadx 8
        pack $frame.docspath.path.entry -side right -expand 1 -fill x

        frame $frame.docspath.buttons
        pack $frame.docspath.buttons -fill x
        button $frame.docspath.buttons.reset -text [_ "Reset"] \
            -command "::dialog_path::reset_docspath $frame"
        button $frame.docspath.buttons.disable -text [_ "Disable"] \
            -command "::dialog_path::disable_docspath $frame"
        pack $frame.docspath.buttons.reset -side left -ipadx 8
        pack $frame.docspath.buttons.disable -side left -ipadx 8

        # scroll to right for long paths
        $frame.docspath.path.entry xview moveto 1
    }

    # add deken path widgets if deken is loaded
    if {[namespace exists ::deken]} {
        labelframe $frame.installpath -text [_ "Externals Install Directory"] \
            -borderwidth 1 -padx 5 -pady 5
        pack $frame.installpath -fill x -anchor s -padx {2m 4m} -pady 2m

        frame $frame.installpath.path
        pack $frame.installpath.path -fill x
        entry $frame.installpath.path.entry -textvariable ::dialog_path::installpath \
            -takefocus 0 -state readonly -readonlybackground $readonly_color
        button $frame.installpath.path.browse -text [_ "Browse"] \
            -command "::dialog_path::browse_installpath $frame"
        pack $frame.installpath.path.browse -side right -fill x -ipadx 8
        pack $frame.installpath.path.entry -side right -expand 1 -fill x

        frame $frame.installpath.buttons
        pack $frame.installpath.buttons -fill x
        button $frame.installpath.buttons.reset -text [_ "Reset"] \
            -command "::dialog_path::reset_installpath $frame"
        button $frame.installpath.buttons.clear -text [_ "Clear"] \
            -command "::dialog_path::clear_installpath $frame"
        pack $frame.installpath.buttons.reset -side left -ipadx 8
        pack $frame.installpath.buttons.clear -side left -ipadx 8

        # scroll to right for long paths
        $frame.installpath.path.entry xview moveto 1
    }
    ::preferencewindow::simplefocus $frame.listbox.box
    return
}

proc ::dialog_path::create_dialog {mytoplevel} {
    ::preferencewindow::create ${mytoplevel} [_ "Pd search path for objects, help, audio, text and other files"] {450 300}
    wm withdraw $mytoplevel

    set my [::preferencewindow::add_frame ${mytoplevel}  [_ "path preferences"]]

    # add widgets
    fill_frame $my 1
    # focus handling on OSX
    ::preferencewindow::simplefocus $my.listbox.box $mytoplevel.nb.buttonframe.ok "::dialog_path::ok $mytoplevel" "::dialog_path::cancel $mytoplevel"
    if {$::windowingsystem eq "aqua"} {
        # unbind ok button when in listbox
        bind $my.listbox.box <FocusIn> "::dialog_path::unbind_return $mytoplevel"
        bind $my.listbox.box <FocusOut> "::dialog_path::rebind_return $mytoplevel"
    }

    pack $my -side top -fill x -expand 1

    # add actions
    ::preferencewindow::add_cancel ${mytoplevel} "::scrollboxwindow::cancel ${mytoplevel}"
    ::preferencewindow::add_apply ${mytoplevel} "::scrollboxwindow::apply ${my} ::dialog_path::commit"

    ::pd_bindings::dialog_bindings $mytoplevel "path"

    # re-adjust height based on optional sections
    update
    wm minsize $mytoplevel [winfo width $mytoplevel] [winfo reqheight $mytoplevel]

    position_over_window $mytoplevel .pdwindow
    raise $mytoplevel
}

# browse for a new Pd user docs path
proc ::dialog_path::browse_docspath {mytoplevel} {
    # set the new docs dir
    set newpath [tk_chooseDirectory -initialdir $::env(HOME) \
                                    -title [_ "Choose Pd documents directory:"]]
    if {$newpath ne ""} {
        set ::dialog_path::docspath $newpath
        set ::dialog_path::installpath [::pd_docsdir::get_externals_path "$::dialog_path::docspath"]
        $mytoplevel.docspath.path.entry xview moveto 1
        return 1
    }
    return 0
}

# ignore the Pd user docs path
proc ::dialog_path::disable_docspath {mytoplevel} {
    set ::dialog_path::docspath [::pd_docsdir::get_disabled_path]
    return 1
}

# reset to the default Pd user docs path
proc ::dialog_path::reset_docspath {mytoplevel} {
    set ::dialog_path::docspath [::pd_docsdir::get_default_path]
    set ::dialog_path::installpath [::pd_docsdir::get_externals_path "$::dialog_path::docspath"]
    $mytoplevel.docspath.path.entry xview moveto 1
    return 1
}

# browse for a new deken installpath, this assumes deken is available
proc ::dialog_path::browse_installpath {mytoplevel} {
    if {![file isdirectory $::dialog_path::installpath]} {
        set initialdir $::env(HOME)
    } else {
        set initialdir $::dialog_path::installpath
    }
    set newpath [tk_chooseDirectory -initialdir $initialdir \
                                    -title [_ "Install externals to directory:"]]
    if {$newpath ne ""} {
        set ::dialog_path::installpath $newpath
        $mytoplevel.installpath.path.entry xview moveto 1
        return 1
    }
    return 0
}

# reset to default deken installpath
proc ::dialog_path::reset_installpath {mytoplevel} {
    set ::dialog_path::installpath [::deken::find_installpath true]
    $mytoplevel.installpath.path.entry xview moveto 1
}

# clear the deken installpath
proc ::dialog_path::clear_installpath {mytoplevel} {
    set ::dialog_path::installpath ""
}

# for focus handling on OSX
proc ::dialog_path::rebind_return {mytoplevel} {
    bind $mytoplevel <KeyPress-Escape> "::dialog_path::cancel $mytoplevel"
    bind $mytoplevel <KeyPress-Return> "::dialog_path::ok $mytoplevel"
    focus $mytoplevel.nb.buttonframe.ok
    return 0
}

# for focus handling on OSX
proc ::dialog_path::unbind_return {mytoplevel} {
    bind $mytoplevel <KeyPress-Escape> break
    bind $mytoplevel <KeyPress-Return> break
    return 1
}

############ pdtk_path_dialog -- dialog window for search path #########
proc ::dialog_path::choosePath {currentpath title} {
    if {$currentpath == ""} {
        set currentpath $::env(HOME)
    }
    return [tk_chooseDirectory -initialdir $currentpath -title $title]
}

proc ::dialog_path::add {} {
    return [::dialog_path::choosePath "" [_ "Add a new path"]]
}

proc ::dialog_path::edit {currentpath} {
    return [::dialog_path::choosePath $currentpath [_ "Edit existing path \[%s\]" $currentpath] ]
}

proc ::dialog_path::commit {new_path} {
    # save buttons and search paths
    set changed false
    if {"$new_path" ne "$::sys_searchpath"} {set changed true}
    set ::sys_searchpath $new_path
    pdsend "pd path-dialog $::sys_use_stdpath $::sys_verbose [pdtk_encode $::sys_searchpath]"
    if {$changed} {::helpbrowser::refresh}

    # save installpath
    if {[namespace exists ::deken]} {
        # clear first so set_installpath doesn't pick up prev value from guiprefs
        set ::deken::installpath ""
        ::deken::set_installpath $::dialog_path::installpath
    }

    # save docspath
    if {[namespace exists ::pd_docsdir]} {
        # run this after since it checks ::deken::installpath value
        ::pd_docsdir::update_path $::dialog_path::docspath
    }
}


# procs for setting variables from the Pd-core
proc ::dialog_path::set_paths {searchpath temppath staticpath} {
    set ::sys_searchpath $searchpath
    set ::sys_temppath $temppath
    set ::sys_staticpath $staticpath
}