
#-------------------------------------------------------------------------------
# Module:     workspace.tk
# Activation: Loaded during GOBLET startup
# Scope:      Splitting the workspace into canvas, messenger and dialog region
#             Scrollbars, separators and alignment of the workspace elements
#             Generic dialog form
#
# Updated: 2003/03/13 Bindings for dialog reconfiguration
#-------------------------------------------------------------------------------



set Workspace .workspace
frame $Workspace
pack $Workspace -side top -after .infobar -fill both -expand yes

set CanvasRegion $Workspace.fcanvas
set InternalLog $Workspace.flogging
set DialogRegion $Workspace.fdialog

proc SplitWorkspace {} {
    global Workspace CanvasRegion InternalLog DialogRegion DialogView \
        BrowserBalance DialogBalance SepWidth ActiveDialog DialogBalance2 \
        DialogSeparator DialogSeparator2
    
    if {[winfo exists $DialogRegion]} {
        set thisDialogBalance 1.0
        if {$DialogBalance<$thisDialogBalance && $ActiveDialog!=""} {
            set thisDialogBalance $DialogBalance
        }
        place $DialogRegion -in $Workspace -relx $thisDialogBalance -rely 0 \
            -relwidth [expr 1-$thisDialogBalance] -relheight 1 -anchor nw

        place $DialogView -in $DialogRegion.sub -x 0 -rely 0 -anchor nw \
            -relwidth 1 -relheight $DialogBalance2
        place $DialogRegion.sub.frame -in $DialogRegion.sub -anchor nw \
            -x 0 -rely $DialogBalance2 \
            -relwidth 1 -relheight [expr 1-$DialogBalance2]

        if {[winfo exists $InternalLog]} {
            if {[winfo exists $CanvasRegion]} {
                place $CanvasRegion -in $Workspace -relx 0 -rely 0 -anchor nw \
                    -relwidth $thisDialogBalance -relheight $BrowserBalance
                place $InternalLog -in $Workspace -relx 0 -rely $BrowserBalance \
                    -relwidth $thisDialogBalance -relheight [expr 1-$BrowserBalance] \
                    -anchor nw
                MakeCanvasSeparator
            } else {
                place $InternalLog -in $Workspace -relx 0 -rely 0 \
                    -relwidth $thisDialogBalance -relheight 1 -anchor nw
            }
        } else {
            place $CanvasRegion -in $Workspace -relx 0 -rely 0 -anchor nw \
                -relwidth $thisDialogBalance -relheight 1
        }
    } else {
        if {[winfo exists $InternalLog]} {
            if {[winfo exists $CanvasRegion]} {
                place $CanvasRegion -in $Workspace -relx 0 -rely 0 -anchor nw \
                    -relwidth 1 -relheight $BrowserBalance
                place $InternalLog -in $Workspace -relx 0 -rely $BrowserBalance \
                    -relwidth 1 -relheight [expr 1-$BrowserBalance] -anchor nw
                MakeCanvasSeparator
            } else {
                place $InternalLog -in $Workspace -relx 0 -rely 0 \
                    -relwidth 1 -relheight 1 -anchor nw
            }
        } else {
            place $CanvasRegion -in $Workspace -relx 0 -rely 0 \
                -relwidth 1 -relheight 1 -anchor nw
        }
    }
}


# Canvas Region

proc InitCanvasRegion {{textMode 0}} {
    global Workspace CanvasRegion c xscroll yscroll savedMaxSize \
        BrowserBalance InternalLog CanvasSeparator CanvasToolbar CanvasView \
        SavedXScrollPos SavedYScrollPos InternalWindowing DialogBalance \
        DialogRegion
    
    set CanvasView $CanvasRegion.view

    set xscroll $CanvasView.xscroll
    set yscroll $CanvasView.yscroll
    if {[winfo exists $xscroll]} {
        set SavedXScrollPos [lindex [$xscroll get] 0]
        set SavedYScrollPos [lindex [$yscroll get] 0]
    } else {
        set SavedXScrollPos 0
        set SavedYScrollPos 0
    }

    destroy $CanvasRegion
    frame $CanvasRegion

    if {$InternalWindowing} {
        SplitWorkspace
    } else {
        if {[winfo exists $InternalLog]} {
            destroy $InternalLog
            pack $CanvasRegion -side top -fill both -expand yes -padx 1m -pady 1m
            ViewMessenger
        } else {
            pack $CanvasRegion -side top -fill both -expand yes -padx 1m -pady 1m
        }
    }
    
    set CanvasToolbar $CanvasRegion.bar
    frame $CanvasToolbar -relief raised -borderwidth 1
    pack $CanvasToolbar -side left -fill y

    frame $CanvasView
    pack $CanvasView -side top -fill both -expand yes

    set c $CanvasView.canvas
    
    if {$textMode==0} {
        canvas $c -bg ivory \
	        -relief sunken -borderwidth 2 \
	        -xscrollcommand "$xscroll set" \
	        -yscrollcommand "$yscroll set"
    } else {
        text $c -bg ivory -font {courier 12 bold} \
            -padx 2m -pady 2m -wrap none -takefocus 1 \
	        -relief sunken -borderwidth 2 \
	        -xscrollcommand "$xscroll set" \
	        -yscrollcommand "$yscroll set"
    }
    bind $c <Button-1> {focus $c}
    # $c create image 10 10 -image wallpaper -anchor nw

    set canvasDelete $CanvasView.delete
    scrollbar $yscroll -command "$c yview" -width 3.5m
    scrollbar $xscroll -orient horiz -command "$c xview" -width 3.5m
    button $canvasDelete -command {DestroyCanvasRegion} -padx 0 -pady 0 \
        -image delbutton

    grid $c \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid $yscroll \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news
    grid $xscroll \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid $canvasDelete \
        -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news

    if {[winfo exists $InternalLog]} {MakeCanvasSeparator}

    grid rowconfig    $CanvasView 0 -weight 1 -minsize 0
    grid columnconfig $CanvasView 0 -weight 1 -minsize 0
}

proc DestroyCanvasRegion {} {
    global CanvasRegion
    destroy $CanvasRegion
    ViewMessenger
}

proc BackupScrollPos {} {
    global CanvasView c SavedXScrollPos SavedYScrollPos

    set xscroll $CanvasView.xscroll
    set yscroll $CanvasView.yscroll
    $c xview moveto $SavedXScrollPos
    $c yview moveto $SavedYScrollPos
    eval $xscroll set [$c xview]
    eval $yscroll set [$c yview]
}

proc MakeCanvasSeparator {} {
    global CanvasRegion CanvasSeparator CanvasView Workspace SepWidth
    set CanvasSeparator $CanvasView.sep
    if {![winfo exists $CanvasView]} {return}
    
    destroy $CanvasSeparator
    frame $CanvasSeparator -height $SepWidth -bg grey
    $CanvasSeparator config -cursor sizing
    bind $CanvasSeparator <Button-1> {
        global InternalWindowing InternalLog BrowserBalance Workspace
        if {![winfo exists $InternalLog] && $InternalWindowing} {
            set BrowserBalance 1.0
            ViewMessenger
        }
        $Workspace config -cursor sizing

        toplevel .volatileBar
        wm geometry .volatileBar \
            [expr [winfo width $CanvasSeparator]]x$SepWidth+[expr \
                [winfo rootx $CanvasSeparator]]+[expr [winfo rooty \
                $CanvasSeparator]]
        frame .volatileBar.bar -height $SepWidth -bg darkgrey
        pack .volatileBar.bar -fill both
        wm overrideredirect .volatileBar 1
    }
    bind $CanvasSeparator <B1-Motion> {
        set movedY [winfo pointery $CanvasSeparator]
        if {$movedY<[expr round([winfo rooty $Workspace]+[winfo height $Workspace]*0.1)]} {
            set movedY [expr round([winfo rooty $Workspace]+[winfo height $Workspace]*0.1)]
        }
        if {$movedY>[expr [winfo rooty $Workspace]+[winfo height $Workspace]-$SepWidth]} {
            set movedY [expr [winfo rooty $Workspace]+[winfo height $Workspace]-$SepWidth]
        }
        wm geometry .volatileBar \
            [expr [winfo width $CanvasSeparator]]x$SepWidth+[expr \
                [winfo rootx $CanvasSeparator]]+$movedY
    }
    bind $CanvasSeparator <ButtonRelease-1> {
        global CanvasSeparator BrowserBalance CanvasRegion InternalLog \
	        InternalWindowing Workspace DialogBalance
        if {!$InternalWindowing} {return}

        set BrowserBalance [expr {([winfo pointery $CanvasRegion] \
            -[winfo rooty $Workspace] +0.01) / [winfo height $Workspace]}]
        if {$BrowserBalance<0.1} {set BrowserBalance 0.1}
        if {$BrowserBalance>1} {set BrowserBalance 1}
        SplitWorkspace
        $Workspace config -cursor left_ptr
        destroy .volatileBar
    }
    grid $CanvasSeparator \
        -row 2 -column 0 -rowspan 1 -columnspan 2 -sticky news
    grid rowconfig    $CanvasView 0 -weight 1 -minsize 0
}


# Dialog Region

proc InitDialogRegion {} {
    global DialogRegion xscroll DialogView DialogCanvas DialogFrame \
        RegisteredDialogs DialogListBox DefPadX DefPadY DialogSeparator
    
    if {[winfo exists $DialogRegion]} {
        $DialogListBox delete 0 end
        foreach item $RegisteredDialogs {
            $DialogListBox insert end $item
        }
        return
    }
    
    # Padding of internal dialogs
    set DefPadX "3m"
    set DefPadY "0m"

    set DialogView $DialogRegion.sub.view

    set xscroll $DialogView.xscroll
    set yscroll $DialogView.yscroll
    frame $DialogRegion
    pack $DialogRegion -side left -fill both -expand yes -padx 1m -pady 1m

    frame $DialogRegion.sub

    MakeDialogSeparator

    grid $DialogSeparator \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky nws
    grid $DialogRegion.sub \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news

    grid rowconfig $DialogRegion 0 -weight 1 -minsize 0
    grid columnconfig $DialogRegion 0 -weight 0 -minsize 0
    grid columnconfig $DialogRegion 1 -weight 1 -minsize 0

    frame $DialogView
    pack $DialogView -side top -fill both
    MakeDialogSeparator2

    set DialogCanvas $DialogView.canvas
    canvas $DialogCanvas \
	    -relief groove -borderwidth 2 \
	    -xscrollcommand "$xscroll set" -yscrollcommand "$yscroll set"

    set dialogDelete $DialogView.delete
    scrollbar $yscroll -command "$DialogCanvas yview" -width 3.5m
    scrollbar $xscroll -orient horiz -command "$DialogCanvas xview" -width 3.5m
    button $dialogDelete -command {DestroyActiveDialog} -padx 0 -pady 0 \
        -image delbutton

    grid $DialogCanvas \
        -row 0 -column 0 -rowspan 1 -columnspan 2 -sticky news
    grid $xscroll \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid $yscroll \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news
    grid $dialogDelete \
        -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news

    grid rowconfig    $DialogView 0 -weight 1 -minsize 0
    grid columnconfig $DialogView 0 -weight 1 -minsize 0
    
    set DialogFrame $DialogCanvas.frame
    set f [frame $DialogFrame]
    $DialogCanvas create window 1 1 -anchor nw -window $f
    
    frame $DialogRegion.sub.frame -relief groove -borderwidth 2
    pack $DialogRegion.sub.frame -side top -fill both -expand yes -ipadx 5m -ipady 5m
    set DialogListBox $DialogRegion.sub.frame.list
    listbox $DialogListBox -width 25 -relief flat -borderwidth 6
    pack $DialogListBox -side top -fill both -expand yes
    foreach item $RegisteredDialogs {
        $DialogListBox insert end $item
    }
    
    bind $DialogListBox <Double-Button-1> {
        ActivateDialog [selection get]
    }
}

proc MakeDialogSeparator {} {
    global DialogRegion DialogSeparator Workspace DialogBalance SepWidth
    set DialogSeparator $DialogRegion.sep
    if {[winfo exists $DialogSeparator]} {return}

    frame $DialogSeparator -width $SepWidth -bg grey
    $DialogSeparator config -cursor sizing
    bind $DialogSeparator <Button-1> {
        $Workspace config -cursor sizing

        toplevel .volatileBar
        wm geometry .volatileBar \
            [expr $SepWidth]x[expr [winfo width $DialogSeparator]]+[expr \
                [winfo rootx $DialogSeparator]]+[expr [winfo rooty \
                $DialogSeparator]]
        frame .volatileBar.bar -width $SepWidth -bg darkgrey
        pack .volatileBar.bar -fill both
        wm overrideredirect .volatileBar 1
    }
    bind $DialogSeparator <B1-Motion> {
        set movedX [winfo pointerx $DialogSeparator]
        if {$movedX<[expr round([winfo rootx $Workspace]+[winfo width $Workspace]*0.1)]} {
            set movedX [expr round([winfo rootx $Workspace]+[winfo width $Workspace]*0.1)]
        }
        if {$movedX>[expr [winfo rootx $Workspace]+[winfo width $Workspace]-$SepWidth]} {
            set movedX [expr [winfo rootx $Workspace]+[winfo width $Workspace]-$SepWidth]
        }
        wm geometry .volatileBar \
            [expr $SepWidth]x[expr [winfo height $DialogSeparator]]+$movedX+[expr \
                [winfo rooty $DialogSeparator]]
    }
    bind $DialogSeparator <ButtonRelease-1> {
        set DialogBalance [expr {([winfo pointerx $DialogRegion] \
            -[winfo rootx $Workspace] +0.01) / [winfo width $Workspace]}]
        if {$DialogBalance<0.1} {set DialogBalance 0.1}
        if {$DialogBalance>0.99} {set DialogBalance 0.99}
        SplitWorkspace
        $Workspace config -cursor left_ptr
        destroy .volatileBar
    }
}

proc MakeDialogSeparator2 {} {
    global DialogRegion DialogSeparator2 DialogView DialogBalance2 SepWidth

    set DialogSeparator2 $DialogView.sep
    if {![winfo exists $DialogView]} {return}
    
    destroy $DialogSeparator2
    frame $DialogSeparator2 -height $SepWidth -bg grey
    $DialogSeparator2 config -cursor sizing
    bind $DialogSeparator2 <Button-1> {
        global DialogSeparator2
        $Workspace config -cursor sizing

        toplevel .volatileBar
        wm geometry .volatileBar \
            [expr [winfo width $DialogSeparator2]]x$SepWidth+[expr \
                [winfo rootx $DialogSeparator2]]+[expr [winfo rooty \
                $DialogSeparator2]]
        frame .volatileBar.bar -height $SepWidth -bg darkgrey
        pack .volatileBar.bar -fill both
        wm overrideredirect .volatileBar 1
    }
    bind $DialogSeparator2 <B1-Motion> {
        set movedY [winfo pointery $DialogSeparator2]
        if {$movedY<[expr round([winfo rooty $Workspace]+[winfo height $Workspace]*0.1)]} {
            set movedY [expr round([winfo rooty $Workspace]+[winfo height $Workspace]*0.1)]
        }
        if {$movedY>[expr [winfo rooty $Workspace]+[winfo height $Workspace]-$SepWidth]} {
            set movedY [expr [winfo rooty $Workspace]+[winfo height $Workspace]-$SepWidth]
        }
        wm geometry .volatileBar \
            [expr [winfo width $DialogSeparator2]]x$SepWidth+[expr \
                [winfo rootx $DialogSeparator2]]+$movedY
    }
    bind $DialogSeparator2 <ButtonRelease-1> {
        global DialogSeparator2 DialogBalance2 DialogRegion \
	        InternalWindowing Workspace
        if {!$InternalWindowing} {return}

        set DialogBalance2 [expr {([winfo pointery $DialogRegion] \
            -[winfo rooty $Workspace] +0.01) / [winfo height $Workspace]}]
        if {$DialogBalance2<0.1} {set DialogBalance2 0.1}
        if {$DialogBalance2>1.0} {set DialogBalance2 1.0}
        SplitWorkspace
        $Workspace config -cursor left_ptr
        destroy .volatileBar
    }
    grid $DialogSeparator2 \
        -row 2 -column 0 -rowspan 1 -columnspan 2 -sticky news
    grid rowconfig    $DialogView 0 -weight 1 -minsize 0
}

proc RegisterDialog {title path procNameActivate procNameUpload} {
    global ActiveDialog RegisteredDialogs RegisteredPath \
        RegisteredConstructor RegisteredUploader Workspace

    if {$ActiveDialog!=""} {
        destroy $RegisteredPath($ActiveDialog)
    }

    set ActiveDialog $title
    set i [lsearch $RegisteredDialogs $ActiveDialog]
    if {$i>=0} {
        set RegisteredDialogs [lreplace $RegisteredDialogs $i $i]
    }
    set RegisteredDialogs [linsert $RegisteredDialogs 0 $ActiveDialog]
    set RegisteredPath($title) $path
    set RegisteredConstructor($title) $procNameActivate
    set RegisteredUploader($title) $procNameUpload

    bind $Workspace <Configure> {AlignActiveDialog}
}

proc ActivateDialog {title} {
    global ActiveDialog RegisteredDialogs RegisteredConstructor \
        RegisteredPath Workspace

    if {$ActiveDialog!=""} {
        destroy $RegisteredPath($ActiveDialog)
        set ActiveDialog ""
    }

    eval $RegisteredConstructor($title)

    bind $Workspace <Configure> {AlignActiveDialog}
}

proc AlignActiveDialog {} {
    global DialogCanvas DialogFrame InternalWindowing RegisteredPath \
        ActiveDialog DialogBalance SepWidth DialogBalance2

    if {$InternalWindowing} {
        SplitWorkspace
        # tkwait visibility $RegisteredPath($ActiveDialog)
        set dummyTimer 0
        after 10 set dummyTimer 1
        vwait dummyTimer

        set width [winfo reqwidth $DialogFrame]
        set height [winfo reqheight $DialogFrame]
        $DialogCanvas config -scrollregion "1 1 $width $height"

        set maxWidth [expr [winfo width .]-80-$SepWidth]
        if {$width>$maxWidth} {set width $maxWidth}
        set DialogBalance \
            [expr 1-($SepWidth.0+$width.0+20)/([winfo width .]-60)]
        if {$DialogBalance<0.0} {set $DialogBalance2 0.0}

        set maxHeight [expr [winfo height .]-90-$SepWidth]
        if {$height>$maxHeight} {set height $maxHeight}
        set DialogBalance2 \
            [expr ($SepWidth.0+$height.0+10)/([winfo height .]-80)]
        if {$DialogBalance2>1.0} {set $DialogBalance2 1.0}
    }

    SplitWorkspace
    InitDialogRegion
}

proc DestroyActiveDialog {} {
    global ActiveDialog RegisteredPath ActiveDialog RegisteredDialogs Workspace

    bind $Workspace <Configure> {}
    if {$ActiveDialog!=""} {
        if {[llength $RegisteredDialogs]>1} {
            destroy $RegisteredPath($ActiveDialog)
            set i [lsearch $RegisteredDialogs $ActiveDialog]
            set RegisteredDialogs [lreplace $RegisteredDialogs $i $i]
            set ActiveDialog [lindex $RegisteredDialogs 0]
            ActivateDialog $ActiveDialog
        } else {
            destroy $RegisteredPath($ActiveDialog)
            set ActiveDialog ""
            set RegisteredDialogs [list]
            InitDialogRegion
            SplitWorkspace
        }
    } else {
        InitDialogRegion
    }
}

proc DisplayInputDialog {title execute label1 label2 body} {
    global WDInput InternalWindowing DialogFrame DefPadX DefPadY \
        GoCommand UploadCommand ActiveDialog 

    if {$ActiveDialog==$title} {return}

    if {$InternalWindowing} {
        set WDInput $DialogFrame.input$execute
        if {![winfo exists $WDInput]} {
            frame $WDInput
        }
        
        RegisterDialog $title $WDInput $execute {}
    } else {
        set WDInput .input
        if {![winfo exists $WDInput]} {
            toplevel $WDInput
            wm title $WDInput $title
            wm resizable $WDInput 0 0
        }
    }

    frame $WDInput.buttons
    pack $WDInput.buttons -padx 3m -pady 3m -side bottom

    button $WDInput.buttons.cancel -text $label2 -command {
        eval $UploadCommand
        if {$InternalWindowing} {
            DestroyActiveDialog
        } else {
            destroy $WDInput
        }
    }

    if {$label1!=""} {
        button $WDInput.buttons.go -text $label1 -command {
            eval $GoCommand
        }

        pack $WDInput.buttons.go $WDInput.buttons.cancel \
            -side left -fill x -padx 3m
    } else {
        pack $WDInput.buttons.cancel -side left -fill x -padx 3m
    }

    frame $WDInput.frame
    
    eval $body
    
    pack $WDInput.frame -padx $DefPadX -pady 5m -side top -anchor w

    if {$InternalWindowing} {
        pack $WDInput -anchor nw
        AlignActiveDialog
    }
}
