#!/bin/sh
#\
exec wish8.4 "$0"
# ======================================================================
# Simple text editor built with [incr Widgets]
# ----------------------------------------------------------------------
#   AUTHOR:  Michael J. McLennan
#    CLASS:  Object-Oriented Programming with [incr Tcl]
# ======================================================================
package require Iwidgets 4.0

option add *edit.width 5i startupFile
option add *edit.height 4i startupFile
option add *Fileselectiondialog.width 4i startupFile
option add *Fileselectiondialog.height 5i startupFile

# ----------------------------------------------------------------------
set FileWindows 0

# ----------------------------------------------------------------------
#  Dialog boxes
# ----------------------------------------------------------------------
iwidgets::messagedialog .notice -title "itkedit: Notice" \
    -bitmap info -buttonboxpos e -modality application
.notice hide OK
.notice hide Help
.notice buttonconfigure Cancel -text "Dismiss"

iwidgets::messagedialog .confirm -title "itkedit: Confirm" \
    -bitmap questhead -modality application
.confirm hide Help
.confirm buttonconfigure OK -text "Yes"
.confirm buttonconfigure Cancel -text "No"

iwidgets::fileselectiondialog .files -title "itkedit: Files" \
    -childsitepos s -modality application
.files hide Help

set PaneMenu "[.files childsite].panes"
iwidgets::optionmenu $PaneMenu -labeltext "Edit Window:"
pack $PaneMenu -pady 6

# ----------------------------------------------------------------------
# USAGE:  file_load
#
# Initiates the process of loading a new text file for editing.
# Pops up a Fileselectiondialog, allowing the user to select a
# file for editing.  If the user pushes the "load" button, the
# file is loaded.
# ----------------------------------------------------------------------
proc file_load {} {
    global FileName PaneMenu

    .files buttonconfigure OK -text "Load"
    if {[.files activate]} {
        set fname [.files get]
        set cmd {
            set fid [open $fname r]
            set text [read $fid]
            close $fid
        }
        if {[catch $cmd err] != 0} {
            .notice configure -bitmap error \
                -text "Cannot load file \"$fname\":\n$err"
            .notice activate
            return
        }

        set pane [$PaneMenu get]
        set win [.edit childsite $pane]
        clear_text $win
        $win.text insert end $text
        $win.text configure -labeltext "file: $fname"

        set FileName($win) $fname
    }
}

# ----------------------------------------------------------------------
# USAGE:  file_save_as
#
# Initiates the process of saving the current text into a particular
# file.  Pops up a Fileselectiondialog, allowing the user to select
# a file for saving.  If the user pushes the "save" button, the
# file is saved.
# ----------------------------------------------------------------------
proc file_save_as {} {
    global FileName PaneMenu

    .files buttonconfigure OK -text "Save"
    if {[.files activate]} {
        set pane [$PaneMenu get]
        set win [.edit childsite $pane]

        set FileName($win) [.files get]

        file_save $win
    }
}

# ----------------------------------------------------------------------
# USAGE:  file_save <win>
#
# Saves the context of <win> into its associated file.  Does the
# dirty work to finish the file_save_as operation.
# ----------------------------------------------------------------------
proc file_save {win} {
    global FileName FileChanged

    set cmd {
        set fid [open $FileName($win) w]
        puts $fid [$win.text get 1.0 end]
        close $fid
        set FileChanged($win) 0
        $win.text configure -labeltext "file: $FileName($win)"
    }
    if {[catch $cmd err] != 0} {
        .notice configure -bitmap error \
            -text "Cannot save file \"$FileName($win)\":\n$err"
        .notice activate
    }
}

# ----------------------------------------------------------------------
# USAGE:  clear_text ?<win>?
#
# Clears the text area associated with <win>, making sure to save
# any pending changes.  If no <win> is specified, then all text
# areas are cleared.
# ----------------------------------------------------------------------
proc clear_text {{areas ""}} {
    global FileName FileChanged FileWindows

    if {$areas == ""} {
        for {set i 0} {$i < $FileWindows} {incr i} {
            set pane "area #[expr $i+1]"
            lappend areas [.edit childsite $pane]
        }
    }

    foreach win $areas {
        if {$FileChanged($win)} {
            set fname [file tail $FileName($win)]
            .confirm configure -text "File \"$fname\" has changed.\nSave changes?"
            if {[.confirm activate]} {
                file_save $win
            }
        }
        $win.text delete 1.0 end
        set FileChanged($win) 0
    }
}

# ----------------------------------------------------------------------
# USAGE:  split_view
#
# Adds another editing pane to the current editor.
# ----------------------------------------------------------------------
proc split_view {} {
    global FileName FileChanged FileWindows PaneMenu

    set pane "area #[incr FileWindows]"
    .edit add $pane -minimum 100
    $PaneMenu insert end $pane

    set win [.edit childsite $pane]

    set FileName($win) untitled.txt
    set FileChanged($win) 0

    iwidgets::scrolledtext $win.text -wrap none -labeltext "file: $FileName($win)" \
        -hscrollmode none -vscrollmode dynamic -visibleitems 1x1
    pack $win.text -expand yes -fill both

    bind [$win.text component text] <KeyPress> "
        set FileChanged($win) 1
    "
}

frame .mbar -borderwidth 2 -relief raised
pack .mbar -side top -fill x

# ----------------------------------------------------------------------
#  FILE menu
# ----------------------------------------------------------------------
menubutton .mbar.file -text "File" -underline 0 -menu .mbar.file.menu
pack .mbar.file -side left -padx 4

menu .mbar.file.menu
.mbar.file.menu add command -label "Load..." \
    -accelerator "  ^L" -underline 0 -command file_load
bind . <Control-KeyPress-l> { .mbar.file.menu invoke "Load..." }

.mbar.file.menu add command -label "Save As..." \
    -accelerator "  ^S" -underline 0 -command file_save_as
bind . <Control-KeyPress-s> { .mbar.file.menu invoke "Save As..." }

.mbar.file.menu add separator
.mbar.file.menu add command -label "Quit" \
    -accelerator "  ^Q" -underline 0 -command {clear_text; exit}
bind . <Control-KeyPress-q> { .mbar.file.menu invoke Quit }

# ----------------------------------------------------------------------
#  VIEW menu
# ----------------------------------------------------------------------
menubutton .mbar.view -text "View" -underline 0 -menu .mbar.view.menu
pack .mbar.view -side left -padx 4

menu .mbar.view.menu
.mbar.view.menu add command -label "Split" \
    -underline 0 -command split_view

# ----------------------------------------------------------------------
#  Editor
# ----------------------------------------------------------------------
iwidgets::panedwindow .edit -orient horizontal
pack .edit -expand yes -fill both

split_view

wm title . "itkedit"
wm protocol . WM_DELETE_WINDOW { .mbar.file.menu invoke Quit }

after idle {
    update idletasks
    wm minsize . [winfo reqwidth .] [winfo reqheight .]
}


