----
[WikiDbImage htext.jpg]
**Usage sample:**
======
set docu(htext) {
[Richard Suchenwirth] 2001-07-20 -
Here's an update to [a little hypertext system] that you might use for online help. It exports a single command:
htext::htext (widget) ?title?
brings up a toplevel showing the specified page
(or an alphabetic index of titles, if not specified). Thus you can use it
for context-sensitive help. You create help pages by just assigning
to the global [[::docu]] array.
Links are displayed underlined and blue (or purple if they have been
visited before), and change the cursor to a
pointing hand. Clicking on a link of course brings up that page. In
addition, you get "Index", "Search" (case-insensitive regexp in titles and
full text), "History", and "Back" links at the bottom of pages.
In a nutshell, you get a tiny browser, an information server, and a search
engine ;-) See also [[htext format]].
}
set {docu(htext format)} {
The [htext] hypertext pages stored in the [[::docu]] array are in a subset
of Wiki format:
* indented lines come in fixed font without evaluation;
* blank lines break paragraphs
* all lines without leading blanks are displayed without explicit linebreak (but possibly word-wrapped)
* a link is the title of another page in brackets (see examples at end).
}
set docu(::docu) {
This global array is used for storing [htext] pages. The advantage is that
source files can be documented just by assigning to ::docu fields, without
creating a dependency on [htext]. After creating a [htext] widget, all
''docu'' documentation is instantly available.
If you wish to have spaces in title, brace the whole thing:
set {docu(An example)} {...}
}
======
**Code**
======
package require msgcat
namespace eval htext {
namespace export htext
variable history {} seen {}
proc htext {w args} {
variable historyLabel
variable searchLabel
variable indexLabel
variable backLabel
if ![winfo exists $w] {
wm title [toplevel $w] Help
text $w.t -border 5 -relief flat -wrap word \
-state disabled -font {Times 9}
pack $w.t -fill both -expand 1
set w $w.t
}
if ![info exists historyLabel] {
set historyLabel [msgcat::mc "History"]
set searchLabel [msgcat::mc "Search"]
set indexLabel [msgcat::mc "Index"]
set backLabel [msgcat::mc "Back"]
}
$w tag config centered -justify center
$w tag config link -foreground blue -underline 1
$w tag config seen -foreground purple4 -underline 1
$w tag bind link <Enter> "$w config -cursor hand2"
$w tag bind link <Leave> "$w config -cursor {}"
$w tag bind link <1> "[namespace current]::click $w %x %y"
$w tag config hdr -font {Times 16}
$w tag config fix -font {Courier 9}
raise $w
if ![llength [array names ::docu $args]] {set args Index}
show $w $args
}
proc click {w x y} {
variable historyLabel
variable searchLabel
variable indexLabel
variable backLabel
set range [$w tag prevrange link [$w index @$x,$y]]
set link [eval $w get $range]
if {[string equal $link $historyLabel]} {
set link History
} elseif {[string equal $link $searchLabel]} {
set link Search
} elseif {[string equal $link $indexLabel]} {
set link Index
} elseif {[string equal $link $backLabel]} {
set link Back
}
if [llength $range] {show $w $link}
}
proc back w {
variable history
set l [llength $history]
set last [lindex $history [expr $l-2]]
set history [lrange $history 0 [expr $l-3]]
show $w $last
}
proc listpage {w list} {
foreach i $list {$w insert end \n; showlink $w $i}
}
proc search w {
$w insert end "\n" {} [msgcat::mc "Search phrase:"] {} " " {}
entry $w.e -textvar [namespace current]::search
$w window create end -window $w.e
focus $w.e
$w.e select range 0 end
bind $w.e <Return> "htext::dosearch $w"
button $w.b -text [msgcat::mc "Search!"] -command "htext::dosearch $w" -pady 0
$w window create end -window $w.b
}
proc dosearch w {
variable search
$w config -state normal
$w insert end "\n\n" {} [msgcat::mc "Search results for '%s':" $search] {} \n {}
foreach i [lsort [array names ::docu]] {
if [regexp -nocase $search $i] {
$w insert end \n; showlink $w $i ;# found in title
} elseif [regexp -nocase -indices -- $search $::docu($i) pos] {
regsub -all \n [string range $::docu($i) \
[expr [lindex $pos 0]-20] [expr [lindex $pos 1]+20]] \
" " context
$w insert end \n
showlink $w $i
$w insert end " - ...$context..."
}
}
$w config -state disabled
}
proc showlink {w link} {
if {[regexp "^image\\://(.*)\$" $link "" imgname]} {
set end0 [$w index end]
$w insert end "\n"
$w image create end -image $imgname
$w insert end "\n"
$w tag add centered $end0 end-1c
return
}
variable seen
set tag link
if {[lsearch -exact $seen $link]>-1} {
lappend tag seen
} else {lappend seen $link}
if {[string equal $link History]} {
set link $historyLabel
} elseif {[string equal $link Search]} {
set link $searchLabel
} elseif {[string equal $link Index]} {
set link $indexLabel
} elseif {[string equal $link Back]} {
set link $backLabel
}
$w insert end $link $tag
}
proc show {w title} {
variable historyLabel
variable searchLabel
variable indexLabel
variable backLabel
variable history
$w config -state normal
$w delete 1.0 end
$w insert end $title hdr \n
switch -- $title {
Back {back $w; return}
History {listpage $w $history}
Index {listpage $w [lsort -dic [array names ::docu]]}
Search {search $w}
default {
if {![info exists ::docu($title)]} {
$w insert end [msgcat::mc "This page was referenced but not written yet."]
} else {
set var 1
foreach i [split $::docu($title) \n] {
if [regexp {^[ \t]+} $i] {
if $var {$w insert end \n\n; set var 0}
$w insert end $i\n fix
continue
}
set i [string trim $i]
if ![string length $i] {$w insert end \n\n; continue}
if !$var {$w insert end \n}
set var 1
while {[regexp {([^[]*)[[]([^]]+)[]](.*)} $i \
-> before link after]} {
$w insert end "$before " {}
showlink $w $link
set i $after
}
$w insert end "$i "
}
}
}
}
$w insert end \n------\n {} $indexLabel link " - " {} $searchLabel link
if [llength $history] {
$w insert end " - " {} $historyLabel link " - " {} $backLabel link
}
$w insert end \n
lappend history $title
$w config -state disabled
}
} ;# end namespace htext
if {[file tail [info script]]==[file tail $argv0]} {
htext::htext .h htext
wm withdraw .
}
======
----
The following procedure will load all files that end with one of the extensions .hlp, .htp or .txt and populate the docu array used by the help system above. I use it to keep all the files describing my applications in a single directory. While this has the drawback of separating the help text from the applications themselves, it allows for better and easier editing from your favorite editor. [EF]
======
proc loadhelp { dir { f_ptn {*.{hlp,htp,txt}}} } {
global docu
foreach fname [glob -nocomplain -tails -directory $dir $f_ptn] {
if { [catch {open [file join $dir $fname]} fd] == 0 } {
set idx [file rootname $fname]
set docu(${idx}) [read $fd]
close $fd
}
}
}
======
----
Implemented with Tk's versatile [text] widget.
----
[Wojciech Kocjan] I have put an image support - putting [[image://anyphotoexistingintk]] shows an image. I have also converted htext package to use msgcat. This is very useful for people like me who would like to supply documentation that looks Polish.
----
Here's how to plug htext into the menu of a [console] (tested on both Win XP and [eTcl]/[PocketPC]):
======
console eval {.menubar.help add command -label Help \
-command {consoleinterp eval {htext::htext .h}}}
======
----
See also [htext as eTcl plugin].
<<categories>> Widget | HTML