1#!/bin/sh
2#\
3exec wish8.4 "$0"
4# ======================================================================
5# Simple text editor built with [incr Widgets]
6# ----------------------------------------------------------------------
7#   AUTHOR:  Michael J. McLennan
8#    CLASS:  Object-Oriented Programming with [incr Tcl]
9# ======================================================================
10package require Iwidgets 4.0
11
12option add *edit.width 5i startupFile
13option add *edit.height 4i startupFile
14option add *Fileselectiondialog.width 4i startupFile
15option add *Fileselectiondialog.height 5i startupFile
16
17# ----------------------------------------------------------------------
18set FileWindows 0
19
20# ----------------------------------------------------------------------
21#  Dialog boxes
22# ----------------------------------------------------------------------
23iwidgets::messagedialog .notice -title "itkedit: Notice" \
24    -bitmap info -buttonboxpos e -modality application
25.notice hide OK
26.notice hide Help
27.notice buttonconfigure Cancel -text "Dismiss"
28
29iwidgets::messagedialog .confirm -title "itkedit: Confirm" \
30    -bitmap questhead -modality application
31.confirm hide Help
32.confirm buttonconfigure OK -text "Yes"
33.confirm buttonconfigure Cancel -text "No"
34
35iwidgets::fileselectiondialog .files -title "itkedit: Files" \
36    -childsitepos s -modality application
37.files hide Help
38
39set PaneMenu "[.files childsite].panes"
40iwidgets::optionmenu $PaneMenu -labeltext "Edit Window:"
41pack $PaneMenu -pady 6
42
43# ----------------------------------------------------------------------
44# USAGE:  file_load
45#
46# Initiates the process of loading a new text file for editing.
47# Pops up a Fileselectiondialog, allowing the user to select a
48# file for editing.  If the user pushes the "load" button, the
49# file is loaded.
50# ----------------------------------------------------------------------
51proc file_load {} {
52    global FileName PaneMenu
53
54    .files buttonconfigure OK -text "Load"
55    if {[.files activate]} {
56        set fname [.files get]
57        set cmd {
58            set fid [open $fname r]
59            set text [read $fid]
60            close $fid
61        }
62        if {[catch $cmd err] != 0} {
63            .notice configure -bitmap error \
64                -text "Cannot load file \"$fname\":\n$err"
65            .notice activate
66            return
67        }
68
69        set pane [$PaneMenu get]
70        set win [.edit childsite $pane]
71        clear_text $win
72        $win.text insert end $text
73        $win.text configure -labeltext "file: $fname"
74
75        set FileName($win) $fname
76    }
77}
78
79# ----------------------------------------------------------------------
80# USAGE:  file_save_as
81#
82# Initiates the process of saving the current text into a particular
83# file.  Pops up a Fileselectiondialog, allowing the user to select
84# a file for saving.  If the user pushes the "save" button, the
85# file is saved.
86# ----------------------------------------------------------------------
87proc file_save_as {} {
88    global FileName PaneMenu
89
90    .files buttonconfigure OK -text "Save"
91    if {[.files activate]} {
92        set pane [$PaneMenu get]
93        set win [.edit childsite $pane]
94
95        set FileName($win) [.files get]
96
97        file_save $win
98    }
99}
100
101# ----------------------------------------------------------------------
102# USAGE:  file_save <win>
103#
104# Saves the context of <win> into its associated file.  Does the
105# dirty work to finish the file_save_as operation.
106# ----------------------------------------------------------------------
107proc file_save {win} {
108    global FileName FileChanged
109
110    set cmd {
111        set fid [open $FileName($win) w]
112        puts $fid [$win.text get 1.0 end]
113        close $fid
114        set FileChanged($win) 0
115        $win.text configure -labeltext "file: $FileName($win)"
116    }
117    if {[catch $cmd err] != 0} {
118        .notice configure -bitmap error \
119            -text "Cannot save file \"$FileName($win)\":\n$err"
120        .notice activate
121    }
122}
123
124# ----------------------------------------------------------------------
125# USAGE:  clear_text ?<win>?
126#
127# Clears the text area associated with <win>, making sure to save
128# any pending changes.  If no <win> is specified, then all text
129# areas are cleared.
130# ----------------------------------------------------------------------
131proc clear_text {{areas ""}} {
132    global FileName FileChanged FileWindows
133
134    if {$areas == ""} {
135        for {set i 0} {$i < $FileWindows} {incr i} {
136            set pane "area #[expr $i+1]"
137            lappend areas [.edit childsite $pane]
138        }
139    }
140
141    foreach win $areas {
142        if {$FileChanged($win)} {
143            set fname [file tail $FileName($win)]
144            .confirm configure -text "File \"$fname\" has changed.\nSave changes?"
145            if {[.confirm activate]} {
146                file_save $win
147            }
148        }
149        $win.text delete 1.0 end
150        set FileChanged($win) 0
151    }
152}
153
154# ----------------------------------------------------------------------
155# USAGE:  split_view
156#
157# Adds another editing pane to the current editor.
158# ----------------------------------------------------------------------
159proc split_view {} {
160    global FileName FileChanged FileWindows PaneMenu
161
162    set pane "area #[incr FileWindows]"
163    .edit add $pane -minimum 100
164    $PaneMenu insert end $pane
165
166    set win [.edit childsite $pane]
167
168    set FileName($win) untitled.txt
169    set FileChanged($win) 0
170
171    iwidgets::scrolledtext $win.text -wrap none -labeltext "file: $FileName($win)" \
172        -hscrollmode none -vscrollmode dynamic -visibleitems 1x1
173    pack $win.text -expand yes -fill both
174
175    bind [$win.text component text] <KeyPress> "
176        set FileChanged($win) 1
177    "
178}
179
180frame .mbar -borderwidth 2 -relief raised
181pack .mbar -side top -fill x
182
183# ----------------------------------------------------------------------
184#  FILE menu
185# ----------------------------------------------------------------------
186menubutton .mbar.file -text "File" -underline 0 -menu .mbar.file.menu
187pack .mbar.file -side left -padx 4
188
189menu .mbar.file.menu
190.mbar.file.menu add command -label "Load..." \
191    -accelerator "  ^L" -underline 0 -command file_load
192bind . <Control-KeyPress-l> { .mbar.file.menu invoke "Load..." }
193
194.mbar.file.menu add command -label "Save As..." \
195    -accelerator "  ^S" -underline 0 -command file_save_as
196bind . <Control-KeyPress-s> { .mbar.file.menu invoke "Save As..." }
197
198.mbar.file.menu add separator
199.mbar.file.menu add command -label "Quit" \
200    -accelerator "  ^Q" -underline 0 -command {clear_text; exit}
201bind . <Control-KeyPress-q> { .mbar.file.menu invoke Quit }
202
203# ----------------------------------------------------------------------
204#  VIEW menu
205# ----------------------------------------------------------------------
206menubutton .mbar.view -text "View" -underline 0 -menu .mbar.view.menu
207pack .mbar.view -side left -padx 4
208
209menu .mbar.view.menu
210.mbar.view.menu add command -label "Split" \
211    -underline 0 -command split_view
212
213# ----------------------------------------------------------------------
214#  Editor
215# ----------------------------------------------------------------------
216iwidgets::panedwindow .edit -orient horizontal
217pack .edit -expand yes -fill both
218
219split_view
220
221wm title . "itkedit"
222wm protocol . WM_DELETE_WINDOW { .mbar.file.menu invoke Quit }
223
224after idle {
225    update idletasks
226    wm minsize . [winfo reqwidth .] [winfo reqheight .]
227}
228
229
230