##################################################
# Übung zur Vorlesung Benutzerschnittstellen
# Aufgabe 1: Photo-Viewer
#
# Autor: Stephan Brumme, 702544

# benoetigte Packages einbinden
package require BWidget
package require Img


##################################################
# GUI-Elemente erzeugen und anordnen
wm title . "Photo Viewer, Stephan Brumme, 702544"
# Menü
menubutton .file
pack .file -side top -anchor w
# nur Eintrag "File"
.file configure -text File -menu .file.m
# nicht abreißbar
menu .file.m -tearoff 0
# "Programm beenden" erlauben
.file.m add command -label Quit -command { exit }


# ID zur Eindeutigkeit der Knoten im Dateibaum
set file_id 0

# Initialisierung und Anordnung
proc FileTree_Create { } {
    # Baum mit Scrollbars erzeugen
    ScrolledWindow .scrollabletree -relief sunken -borderwidth 2
    set tree [Tree .tree -borderwidth 0 -highlightthickness 0 \
            -opencmd "FileTree_OnOpen"]
    .scrollabletree setwidget $tree

    # links plazieren
    pack .scrollabletree -side left -fill y

    # alle Laufwerk erkennen
    foreach drive [file volume] {
        # und in den Baum einfügen
        .tree insert end root drive$drive \
                -text [string index $drive 0]: \
                -data $drive \
                -open 0 \
                -drawcross allways \
                -image [Bitmap::get openfold]
    }

    # Bild öffnen per Mausklick
    .tree configure -selectcommand "FileTree_OnShowPicture"
}


# ein Verzeichnis auslesen und in den Baum einfügen
proc FileTree_ScanDirectory { tree node path } {
    # nur neu lesen, wenn drawcross auf "allways"
    if {[$tree itemcget $node -drawcross] == "allways"} {
        # benötigte Variablen
        set list_of_directories {}
        set list_of_files {}
        global file_id

        # Verzeichnisse und Dateien erkennen
        foreach f [glob -nocomplain [file join $path "*"]] {
            set filename [file tail $f]
            if { [file isdirectory $f] } {
                lappend list_of_directories $filename
            } else {
                # nur gängige Bilder akzeptieren
                if { [regexp -nocase {(jpg$)|(jpeg$)|(gif$)|(png$)} $filename] } {
                    lappend list_of_files $filename
                }
            }
        }

        # Verzeichnisse sortiert ausgeben
        set sorted_directories [lsort -dictionary $list_of_directories]
        foreach filename $sorted_directories {
            $tree insert end $node node$file_id \
                        -text $filename \
                        -data "$path$filename\\" \
                        -image [Bitmap::get folder] \
                        -drawcross allways
            # neue eindeutige ID
            incr file_id
        }

        # Dateien sortiert ausgeben
        set sorted_files [lsort -dictionary $list_of_files]
        foreach filename $sorted_files {
            $tree insert end $node node$file_id \
                    -text $filename \
                    -data "$path$filename" \
                    -image [Bitmap::get file]
            # neue eindeutige ID
            incr file_id
        }

        # Teilbaum braucht nicht mehr neu eingelesen werden
        # markiert durch Änderung von drawcross in "auto""
        $tree itemconfigure $node -drawcross auto
    }
}


# Unterverzeichnis einlesen, wenn Teilbaum geöffnet wird
proc FileTree_OnOpen { node } {
    set subdir [.tree itemcget $node -data]
    FileTree_ScanDirectory .tree $node $subdir
}

# Bild anzeigen
proc FileTree_OnShowPicture { tree node } {
    set filename [$tree itemcget $node -data]
    # wenn Verzeichnis, dann wechseln
    if { [file isdirectory $filename] } {
        FileTree_OnOpen $node
        $tree opentree $node 0
    } else  {
    # sonst Bild anzeigen
        PictureCanvas_Show $filename
    }
}


# Initialisierung und Anordnung
proc PictureCanvas_Create { } {
    # Widgets erzeugen
    canvas .view
    label  .info

    # Scrollbars für die Bildanzeige (namens .view)
    scrollbar .viewhscrollbar -command ".view xview" -orient horiz
    scrollbar .viewvscrollbar -command ".view yview" -orient vertical
    .view configure -xscrollcommand ".viewhscrollbar set" \
                    -yscrollcommand ".viewvscrollbar set"

    # und alles anzeigen
    pack .info -side bottom -fill x
    pack .viewhscrollbar -side bottom -fill x
    pack .viewvscrollbar -side right -fill y
    pack .view -side top -fill both -expand 1
}

# Bild laden und anzeigen
proc PictureCanvas_Show { filename } {
    # Bild laden
    set handle [image create photo -file $filename]
    # anzeigen (vorher altes Bild löschen)
    .view delete all
    .view create image 0 0 -image $handle -anchor nw
    # Informationen extrahieren
    set img_width [image width $handle]
    set img_height [image height $handle]
    set img_filesize [file size $filename]
    set img_name [file tail $filename]
    # Scrollbars anpassen
    .view configure -scrollregion "0 0 $img_width $img_height"

    # und die Infos anzeigen
    .info configure -text \
            "Name:   $img_name   Size:   $img_filesize   Width:   $img_width   Height:   $img_height"
}


# Baum zur Navigation im Dateisystem erzeugen
FileTree_Create
# Vorschaufenster erzeugen
PictureCanvas_Create