JOB 17-02-11
Yes, Tkhtml 3.0 is still alive !
Beside some other packages, you need the html3widget -
A TclOO Tkhtml 3.0 megawidget - example of how to render html+css which is a megawidget implementation based on Tkhtml 3.0.
Attributes edit
- name
- HelpViewer Application
- The complete package can be downloaded from here
- http://www.johann-oberdorfer.eu/blog/2017/04/10/17-10-04_helpviewer/
- latest release
- 3.0.2
- release time
- 2017-04
- contact
- JOB
Recent changes:
Here is the code (although I would suggest to use the link stated above, where the source most likely is up-to-date):
# -------------------------------------------------------------------------
# helpviewer.tcl
# -------------------------------------------------------------------------
# (c) 2016, Johann Oberdorfer - Engineering Support | CAD | Software
# johann.oberdorfer [at] googlemail.com
# www.johann-oberdorfer.eu
# -------------------------------------------------------------------------
# This source file is distributed under the BSD license.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the BSD License for more details.
#
# Credits:
# This software related on the the helpviewer application originally
# created by Ramon Ribó (RAMSAN) ramsan@cimne.upc.es.
# (http://gid.cimne.upc.es/ramsan) for his version of the
# Thank you.
#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
package provide helpviewer 3.0
# lappend auto_path [file dirname [info script]]
set dir [file dirname [info script]]
lappend auto_path [file join $dir "hvimages"]
# requiring exactly 2.0 to avoid getting the one from Activestate
package require -exact Tkhtml 3.0
package require -exact BWidget 1.9.10
package require BWidget_patch
Widget::theme 1
package require fileutil
package require hvimages
package require html3widget
# package is optional
catch { package require Pan }
if { [info command tkTabToWindow] == "" } {
proc tkTabToWindow {w} {
focus $w
after 100 {
set w [focus]
if {[string equal [winfo class $w] Entry]} {
$w selection range 0 end
$w icursor end
}
}
}
}
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
namespace eval HelpViewer {
variable HelpBaseDir
variable LastFileList
# These images are used in place of GIFs or of form elements
#
if { [lsearch [image names] smgray] == -1 } {
image create photo smgray -data {
R0lGODdhOAAYAPAAALi4uAAAACwAAAAAOAAYAAACI4SPqcvtD6OctNqLs968+w+G4kiW5omm
6sq27gvH8kzX9m0VADv/
}
image create photo nogifbig -data {
R0lGODdhJAAkAPEAAACQkADQ0PgAAAAAACwAAAAAJAAkAAACmISPqcsQD6OcdJqKM71PeK15
AsSJH0iZY1CqqKSurfsGsex08XuTuU7L9HywHWZILAaVJssvgoREk5PolFo1XrHZ29IZ8oo0
HKEYVDYbyc/jFhz2otvdcyZdF68qeKh2DZd3AtS0QWcDSDgWKJXY+MXS9qY4+JA2+Vho+YPp
FzSjiTIEWslDQ1rDhPOY2sXVOgeb2kBbu1AAADv/
}
image create photo nogifsm -data {
R0lGODdhEAAQAPEAAACQkADQ0PgAAAAAACwAAAAAEAAQAAACNISPacHtD4IQz80QJ60as25d
3idKZdR0IIOm2ta0Lhw/Lz2S1JqvK8ozbTKlEIVYceWSjwIAO///
}
}
if { [lsearch [image names] appbook16] == -1 } {
image create photo appbook16 -data {
R0lGODlhEAAQAIQAAPwCBAQCBDyKhDSChGSinFSWlEySjCx+fHSqrGSipESO
jCR6dKTGxISytIy6vFSalBxydAQeHHyurAxubARmZCR+fBx2dDyKjPz+/MzK
zLTS1IyOjAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVkICCOZGmK
QXCWqTCoa0oUxnDAZIrsSaEMCxwgwGggHI3E47eA4AKRogQxcy0mFFhgEW3M
CoOKBZsdUrhFxSUMyT7P3bAlhcnk4BoHvb4RBuABGHwpJn+BGX1CLAGJKzmK
jpF+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0K
qSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpo
dHRwOi8vd3d3LmRldmVsY29yLmNvbQA7
}
image create photo appbookopen16 -data {
R0lGODlhEAAQAIUAAPwCBAQCBExCNGSenHRmVCwqJPTq1GxeTHRqXPz+/Dwy
JPTq3Ny+lOzexPzy5HRuVFSWlNzClPTexIR2ZOzevPz29AxqbPz6/IR+ZDyK
jPTy5IyCZPz27ESOjJySfDSGhPTm1PTizJSKdDSChNzWxMS2nIR6ZKyijNzO
rOzWtIx+bLSifNTGrMy6lIx+ZCRWRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAae
QEAAQCwWBYJiYEAoGAFIw0E5QCScAIVikUgQqNargtFwdB9KSDhxiEjMiUlg
HlB3E48IpdKdLCxzEAQJFxUTblwJGH9zGQgVGhUbbhxdG4wBHQQaCwaTb10e
mB8EBiAhInp8CSKYIw8kDRSfDiUmJ4xCIxMoKSoRJRMrJyy5uhMtLisTLCQk
C8bHGBMj1daARgEjLyN03kPZc09FfkEAIf5oQ3JlYXRlZCBieSBCTVBUb0dJ
RiBQcm8gdmVyc2lvbiAyLjUNCqkgRGV2ZWxDb3IgMTk5NywxOTk4LiBBbGwg
cmlnaHRzIHJlc2VydmVkLg0KaHR0cDovL3d3dy5kZXZlbGNvci5jb20AOw==
}
image create photo filedocument16 -data {
R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJSWjPz+/Ozq7GxqbJyanPT29HRy
dMzOzDQyNIyKjERCROTi3Pz69PTy7Pzy7PTu5Ozm3LyqlJyWlJSSjJSOhOzi
1LyulPz27PTq3PTm1OzezLyqjIyKhJSKfOzaxPz29OzizLyidIyGdIyCdOTO
pLymhOzavOTStMTCtMS+rMS6pMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaQ
QIAQECgajcNkQMBkDgKEQFK4LFgLhkMBIVUKroWEYlEgMLxbBKLQUBwc52Hg
AQ4LBo049atWQyIPA3pEdFcQEhMUFYNVagQWFxgZGoxfYRsTHB0eH5UJCJAY
ICEinUoPIxIcHCQkIiIllQYEGCEhJicoKYwPmiQeKisrKLFKLCwtLi8wHyUl
MYwM0tPUDH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24g
Mi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZl
ZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=
}
image create photo viewmag16 -data {
R0lGODlhEAAQAIUAAPwCBCQmJDw+PAwODAQCBMza3NTm5MTW1HyChOTy9Mzq
7Kze5Kzm7OT29Oz6/Nzy9Lzu7JTW3GTCzLza3NTy9Nz29Ize7HTGzHzK1AwK
DMTq7Kzq9JTi7HTW5HzGzMzu9KzS1IzW5Iza5FTK1ESyvLTa3HTK1GzGzGzG
1DyqtIzK1AT+/AQGBATCxHRydMTCxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ8
QIAQEBAMhkikgFAwHAiC5FCASCQUCwYiKiU0HA9IRAIhSAcTSuXBsFwwk0wy
YNBANpyOxPMxIzMgCyEiHSMkGCV+SAQQJicoJCllUgBUECEeKhAIBCuUSxMK
IFArBIpJBCxmLQQuL6eUAFCusJSzr7GLArS5Q7O1tmZ+QQAh/mhDcmVhdGVk
IGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3
LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVs
Y29yLmNvbQA7
}
}
}
proc HelpViewer::GiveLastFile { w } {
variable LastFileList
set retval ""
catch {
set w [winfo toplevel $w]
set retval $LastFileList($w)
}
return $retval
}
proc HelpViewer::EnterLastFile { w file } {
variable LastFileList
set w [winfo toplevel $w]
set LastFileList($w) $file
}
proc HelpViewer::LoadRef { w new { enterinhistory 1 } } {
global tcl_platform
if { [regexp {http:/localhost/cgi-bin/man/man2html\?(\w+)\+(\w+)} $new {} sec word] } {
SearchManHelpFor $w $word $sec
return
} elseif { $new != "" && [regexp {[a-zA-Z]+[a-zA-Z]:.*} $new] } {
regexp {http:/.*} $new url
if { [regexp {:/[^/]} $url] } {
regsub {:/} $url {://} url
}
if { $tcl_platform(platform) != "windows"} {
set comm [auto_execok konqueror]
if { $comm == "" } {
set comm [auto_execok netscape]
}
if { $comm == "" } {
tk_messageBox -icon warning -message \
"Check url: $url in your web browser." -type ok
} else {
exec $comm $url &
}
} else {
global env
if {[file exists [file join $env(ProgramFiles) "internet explorer" iexplore.exe]]} {
exec [file join $env(ProgramFiles) "internet explorer" iexplore.exe] $url &
} else {
tk_messageBox -icon warning -message \
"Check url: $url in your web browser." -type ok
}
}
return
}
if {$new!=""} {
set LastFile [GiveLastFile $w]
if { [string match \#* [file tail $new]] } {
set new $LastFile[file tail $new]
}
set pattern $LastFile#
set len [string length $pattern]
incr len -1
if {[string range $new 0 $len]==$pattern} {
incr len
$w yview [string range $new $len end]
if { $enterinhistory } {
History::Add $new
}
} elseif { [regexp {(.*)\#(.*)} $new {} file tag] } {
LoadFile $w $file $enterinhistory $tag
} else {
LoadFile $w $new $enterinhistory
}
}
}
proc HelpViewer::Load { w } {
global lastDir
set filetypes {
{{Html Files} {.html .htm}}
{{All Files} *}
}
set f [tk_getOpenFile -initialdir $lastDir -filetypes $filetypes]
if {$f!=""} {
set lastDir [file dirname $f]
LoadFile $w $f
}
}
# Clear the screen.
#
proc HelpViewer::ClearHtmlWidget { } {
variable hwidget
# hiding the search widget automatically
# clears all search tags in the html widget as well
$hwidget hideSearchWidget
$hwidget reset
}
proc HelpViewer::ReadFile {name} {
#
# read html file and try to detect charset
# return value is a string holding all the html stuff
#
if { [file dirname $name] == "." } {
set name [file tail $name]
}
if {[catch {open $name r} fp]} {
tk_messageBox -icon error -message $fp -type ok
return {}
} else {
fconfigure $fp -translation binary
set r [read $fp [file size $name]]
close $fp
# attempt to detect charset="UTF-8" !
if { [regexp {(?i)<meta\s+[^>]*charset=utf-8[^>]*>} $r] ||
[string first "charset=utf-8" [string tolower $r]] != -1 ||
[string first "charset=\"utf-8\"" [string tolower $r]] != -1 } {
set fp [open $name r]
fconfigure $fp -encoding utf-8
set r [read $fp]
close $fp
}
return $r
}
}
# Load a file into the HTML widget
#
proc HelpViewer::LoadFile {hwidget name { enterinhistory 1 } { tag "" } } {
variable HelpBaseDir
global HelpPriv
if { $name == "" } { return }
if { [file isdir $name] } {
# name is a directory
set HelpBaseDir $name
set files [glob -nocomplain -dir $name *]
set ipos [lsearch -regexp $files {(?i)(index|contents|_toc)\.(htm|html)}]
if { $ipos != -1 } {
set name [lindex $files $ipos]
} else {
return
}
} else {
# name refers to a file
set HelpBaseDir [file dirname $name]
}
set html [ReadFile $name]
if {$html == ""} {
return
}
ClearHtmlWidget
EnterLastFile $hwidget $name
if { $enterinhistory } {
if { $tag == "" } {
History::Add $name
} else {
History::Add $name#$tag
}
}
$hwidget setbasedir $HelpBaseDir
$hwidget parse -final $html
if { $tag != "" } {
update idletasks
$hwidget yview $tag
}
TryToSelect $name
variable SearchPos
set SearchPos ""
}
# Refresh the current file.
#
proc HelpViewer::Refresh {hwidget args} {
set LastFile [GiveLastFile $hwidget]
if {![info exists LastFile] || ![winfo exists $hwidget] } return
LoadFile $hwidget $LastFile 0
}
proc HelpViewer::ResolveUri { args } {
return [file join [file dirname [lindex $args 0]] [lindex $args 1]]
}
proc HelpViewer::FillDir { tree node } {
variable HelpBaseDir
if { $node == "root" } {
set dir $HelpBaseDir
} else {
set dir [lindex [$tree itemcget $node -data] 1]
}
set idxfolder 0
set files ""
foreach i [glob -nocomplain -dir $dir *] {
lappend files [file tail $i]
}
foreach i [lsort -dictionary $files] {
set fullpath [file join $dir $i]
regsub {^[0-9]+} $i {} name
regsub -all {\s} $fullpath _ item
if { [file isdir $fullpath] } {
# exclude special directories ...
if { [string equal -nocase $i "images"] } { continue }
if { [string equal -nocase $i "externals"] } { continue }
if { [string equal -nocase $i "lib"] } { continue }
$tree insert $idxfolder $node $item \
-image appbook16 -text $name \
-data [list folder $fullpath] -drawcross allways
incr idxfolder
} elseif { [string match .htm* [file ext $i]] } {
set name [file root $i]
$tree insert end $node $item \
-image filedocument16 -text $name \
-data [list file $fullpath]
}
}
}
proc HelpViewer::moddir { idx tree node } {
variable HelpBaseDir
if { $idx && [$tree itemcget $node -drawcross] == "allways" } {
FillDir $tree $node
$tree itemconfigure $node -drawcross auto
if { [llength [$tree nodes $node]] } {
$tree itemconfigure $node -image appbookopen16
} else {
$tree itemconfigure $node -image appbook16
}
} else {
if { [lindex [$tree itemcget $node -data] 0] == "folder" } {
switch $idx {
0 { set img appbook16 }
1 { set img appbookopen16 }
}
$tree itemconfigure $node -image $img
}
}
}
proc HelpViewer::KeyPress { a } {
variable tree
variable searchstring
set node [$tree selection get]
if { [llength $node] != 1 } { return }
append searchstring $a
after 300 [list set HelpViewer::searchstring ""]
if { [$tree itemcget $node -open] == 1 && [llength [$tree nodes $node]] > 0 } {
set parent $node
set after 1
} else {
set parent [$tree parent $node]
set after 0
}
foreach i [$tree nodes $parent] {
if { !$after } {
if { $i == $node } {
if { [string length $HelpViewer::searchstring] > 1 } {
set after 2
} else {
set after 1
}
}
}
if { $after == 2 && [string match -nocase $HelpViewer::searchstring* \
[$tree itemcget $i -text]] } {
$tree selection clear
$tree selection set $i
$tree see $i
return
}
if { $after == 1 } { set after 2 }
}
foreach i [$tree nodes [$tree parent $node]] {
if { $i == $node } { return }
if { [string match -nocase $HelpViewer::searchstring* [$tree itemcget $i -text]] } {
$tree selection clear
$tree selection set $i
$tree see $i
return
}
}
}
proc HelpViewer::Select { tree num node } {
variable hwidget
if { $node == "" } {
set node [$tree selection get]
if { [llength $node] != 1 } { return }
} elseif { ![$tree exists $node] } {
return
}
if { $num >= 1 } {
if { [$tree itemcget $node -open] == 0 } {
$tree itemconfigure $node -open 1
set idx 1
} else {
$tree itemconfigure $node -open 0
set idx 0
}
moddir $idx $tree $node
if { $num == 1 && $idx == 0 } {
return
}
# set selection and ...
# hans: bring current selection onto the screen
$tree selection set $node
$tree see $node
if { [llength [$tree selection get]] == 1 } {
set data [$tree itemcget [$tree selection get] -data]
if { $num >= 1 && $num <= 2 } {
LoadFile $hwidget [lindex $data 1]
}
}
return
}
}
proc HelpViewer::TryToSelect { name } {
variable HelpBaseDir
variable tree
set nameL [file split $name]
set level [llength [file split $HelpBaseDir]]
set node root
while 1 {
set found 0
foreach i [$tree nodes $node] {
if { [lindex [$tree itemcget $i -data] 1] == [eval file join [lrange $nameL 0 $level]] } {
set found 1
break
}
}
if { !$found } { return }
if { [lindex [$tree itemcget $i -data] 0] == "folder" } {
if { [$tree itemcget $i -open] == 0 } {
$tree itemconfigure $i -open 1
}
moddir 1 $tree $i
}
if { $level == [llength $nameL]-1 } {
Select $tree 3 $i
return
}
set node $i
incr level
}
}
proc HelpViewer::CenterWindow {w wparent} {
wm withdraw $w
update idletasks
set top [winfo toplevel [winfo parent $w]]
set width [winfo reqwidth $w]
set height [winfo reqheight $w]
if { [wm state $top] == "withdrawn" } {
set x [expr [winfo screenwidth $top]/2-$width/2]
set y [expr [winfo screenheight $top]/2-$height/2]
} else {
set x [expr [winfo x $top]+[winfo width $top]/2-$width/2]
set y [expr [winfo y $top]+[winfo height $top]/2-$height/2]
}
if { $x < 0 } { set x 0 }
if { $y < 0 } { set y 0 }
wm geom $w ${width}x${height}+${x}+$y
wm deiconify $w
update idletasks
wm geom $w [wm geom $w]
focus $w
}
proc HelpViewer::ExitCmd {{wbase ""}} {
variable callbackcmd
if {$callbackcmd != ""} {
catch {uplevel $callbackcmd}
}
if {$wbase != "" && [winfo exists $wbase]} {
destroy $wbase
} else {
exit 0
}
}
proc HelpViewer::getTreeWidget {} {
variable tree
return $tree
}
proc HelpViewer::getTreeRootName {} {
return "root"
}
proc HelpViewer::getHelpViewerScale {} {
variable hwidget
return [$hwidget fontScaleCmd "getscale"]
}
proc HelpViewer::setHelpViewerScale {scale} {
variable hwidget
$hwidget setscale $scale
}
# -----------------------------------------------------------------------------
# main dialog
# -----------------------------------------------------------------------------
proc HelpViewer::HelpWindow { file_or_dir {base .help} {geom ""} {title ""} {cmd ""} } {
variable HelpBaseDir
variable hwidget
variable tree
variable searchlistbox1
variable searchlistbox2
variable notebook
variable callbackcmd
global lastDir tcl_platform argv0
set callbackcmd $cmd
if { $tcl_platform(platform) != "windows" } {
option add *Scrollbar*Width 10
option add *Scrollbar*BorderWidth 1
option add *Button*BorderWidth 1
}
option add *Menu*TearOff 0
catch { destroy $base }
if { $title == "" } { set title Help }
# could be either a directory or a file reference:
# ------------------------------------------------
# set file_or_dir [file normalize $file_or_dir]
if { [file isdirectory $file_or_dir] } {
set HelpBaseDir $file_or_dir
} else {
set HelpBaseDir [file dirname $file_or_dir]
}
# -----------------------------------------------
# puts $HelpBaseDir
if { [info procs InitWindow] != "" } {
InitWindow $base $title PostHelpViewerWindowGeom
} else {
toplevel $base
wm title $base $title
}
wm withdraw $base
wm protocol $base WM_DELETE_WINDOW "[namespace current]::ExitCmd $base"
#set pw [PanedWindow $base.pw \
# -activator button \
# -side top \
# -pad 5]
set pw [ttk::panedwindow $base.pw \
-orient "horizontal"]
$pw add [set pane1 [ttk::frame $base.pane1]] ;# -weight 5
$pw add [set pane2 [ttk::frame $base.pane2]] ;# -weight 95
NoteBook $pane1.nb \
-homogeneous 1 \
-bd 1 \
-internalborderwidth 3 \
-bg "#EDF3FE" \
-activebackground "#EDF3FE" \
-disabledforeground "#EDF3FE"
pack $pane1.nb -side top -fill both -expand true
set notebook $pane1.nb
set f1 [$pane1.nb insert end tree -text "Contents" -image appbook16]
set sw [ScrolledWindow $f1.lf -relief flat -borderwidth 0]
pack $sw -fill both -expand yes
set tree [Tree $sw.tree -bg white\
-width 15 \
-relief flat \
-borderwidth 0 \
-highlightthickness 0 \
-redraw 1 \
-deltay 18 \
-bg "#EDF3FE" \
-opencmd "HelpViewer::moddir 1 $sw.tree" \
-closecmd "HelpViewer::moddir 0 $sw.tree"]
$sw setwidget $tree
# font metrics:
set font [option get $tree font Font]
if { $font == "" } {
set font "TkDefaultFont"
}
catch {
$tree configure -deltay [expr [font metrics $font -linespace]]
}
if { $::tcl_platform(platform) != "windows" } {
$tree configure \
-selectbackground "#48c96f" \
-selectforeground white
}
$pane1.nb itemconfigure tree -raisecmd "focus $tree"
if {[string equal "unix" $::tcl_platform(platform)]} {
bind $tree.c <4> { %W yview scroll -5 units }
bind $tree.c <5> { %W yview scroll 5 units }
}
$tree bindText <ButtonPress-1> "HelpViewer::Select $tree 1"
$tree bindText <Double-ButtonPress-1> "HelpViewer::Select $tree 2"
$tree bindImage <ButtonPress-1> "HelpViewer::Select $tree 1"
$tree bindImage <Double-ButtonPress-1> "HelpViewer::Select $tree 2"
$tree bindText <Control-ButtonPress-1> "HelpViewer::Select $tree 3"
$tree bindImage <Control-ButtonPress-1> "HelpViewer::Select $tree 3"
$tree bindText <Shift-ButtonPress-1> "HelpViewer::Select $tree 4"
$tree bindImage <Shift-ButtonPress-1> "HelpViewer::Select $tree 4"
# dirty trick
foreach i [bind $tree.c] {
bind $tree.c $i "+[list after idle [list HelpViewer::Select $tree 0 {}]]"
}
bind $tree.c <Return> "HelpViewer::Select $tree 1 {}"
bind $tree.c <KeyPress> "if \[string is wordchar -strict {%A}\] {HelpViewer::KeyPress %A}"
bind $tree.c <Alt-KeyPress-Left> ""
bind $tree.c <Alt-KeyPress-Right> ""
bind $tree.c <Alt-KeyPress> { break }
set f2 [$pane1.nb insert end search -text "Search" -image viewmag16]
set fs [ttk::frame $f2.search]
pack $fs -side top -fill x
label $fs.l1 -text "S:" -bg "#EDF3FE"
entry $fs.e1 -textvariable HelpViewer::searchstring -bg "#EDF3FE"
pack $fs.l1 -side left
pack $fs.e1 -side right -fill x -expand true
$pane1.nb itemconfigure search -raisecmd "tkTabToWindow $fs.e1"
bind $fs.e1 <Return> "focus $f2.lf1.lb; HelpViewer::SearchInAllHelp"
set sw [ScrolledWindow $f2.lf1 -relief sunken]
pack $sw -fill both -expand yes
set searchlistbox1 \
[listbox $f2.lf1.lb \
-listvar HelpViewer::SearchFound \
-bg "#EDF3FE" \
-exportselection 0]
$f2.lf1 setwidget $searchlistbox1
bind $searchlistbox1 <FocusIn> "if { \[%W curselection\] == {} } { %W selection set 0 }"
bind $searchlistbox1 <ButtonPress-1> "focus $f2.lf2.lb; HelpViewer::SearchInAllHelpL1; HelpViewer::SearchCmd"
bind $searchlistbox1 <Return> "focus $f2.lf2.lb; HelpViewer::SearchInAllHelpL1; HelpViewer::SearchCmd"
set sw [ScrolledWindow $f2.lf2 -relief sunken]
pack $sw -fill both -expand yes
set searchlistbox2 \
[listbox $f2.lf2.lb \
-listvar HelpViewer::SearchFound2 \
-bg #EDF3FE \
-exportselection 0]
$f2.lf2 setwidget $searchlistbox2
bind $searchlistbox2 <FocusIn> "if { \[%W curselection\] == {} } { %W selection set 0 }"
bind $searchlistbox2 <ButtonPress-1> "HelpViewer::SearchInAllHelpL2; HelpViewer::SearchCmd"
bind $searchlistbox2 <Return> "HelpViewer::SearchInAllHelpL2; HelpViewer::SearchCmd"
set HelpViewer::SearchFound ""
set HelpViewer::SearchFound2 ""
$pane1.nb compute_size
$pane1.nb raise tree
# set pane2 [$pw add -weight $weight2]
set sw [ScrolledWindow $pane2.lf -relief sunken -borderwidth 0]
pack $sw -fill both -expand yes
# -----------------------------------------------------------------------------
# create html3widget
# -----------------------------------------------------------------------------
html3widget::html3widget $sw.h \
-width 550 \
-height 500
set hwidget $sw.h
$sw setwidget $hwidget
bind [$hwidget get_htmlwidget] <1> \
"+[namespace current]::HrefBinding $hwidget %x %y"
frame $base.buts -bg grey93
Button $base.buts.b1 \
-image $::hv_images(draw-arrow-back) \
-command "History::GoBackward $hwidget" \
-relief link \
-helptext "Go Backward..."
Button $base.buts.b2 \
-image $::hv_images(draw-arrow-forward) \
-command "History::GoForward $hwidget" \
-relief link \
-helptext "Go Forward..."
menubutton $base.buts.b3 -text "More..." -bg grey93 -fg DarkGrey -relief flat \
-menu $base.buts.b3.m -activebackground grey93
menu $base.buts.b3.m
$base.buts.b3.m add command \
-label "Home" -acc "" \
-command "History::GoHome $hwidget" \
-image $::hv_images(go-home-4) \
-compound left
$base.buts.b3.m add command \
-label "Previus" -acc "Alt-Left" \
-command "History::GoBackward $hwidget" \
-image $::hv_images(draw-arrow-back) \
-compound left
$base.buts.b3.m add command \
-label "Next" -acc "Alt-Right" \
-command "History::GoForward $hwidget" \
-image $::hv_images(draw-arrow-forward) \
-compound left
$base.buts.b3.m add separator
$base.buts.b3.m add command \
-label "Search in page..." -acc "Ctrl+F" \
-command "focus $hwidget; HelpViewer::SearchWindow" \
-image $::hv_images(system-search) \
-compound left
$base.buts.b3.m add command \
-label "Close Search Dialog" -acc "" \
-command "$hwidget hideSearchWidget" \
-image $::hv_images(emblem-unreadable) \
-compound left
$base.buts.b3.m add separator
$base.buts.b3.m add command \
-label " Increase Viewer Font / Zoom +" -acc "Ctrl+Plus" \
-command "$hwidget fontScaleCmd plus" \
-compound left
$base.buts.b3.m add command \
-label " Decrease Viewer Font / Zoom -" -acc "Ctrl+Minus" \
-command "$hwidget fontScaleCmd minus" \
-compound left
Button $base.buts.b4 \
-image $::hv_images(emblem-unreadable) \
-command "[namespace current]::ExitCmd $base" \
-relief link \
-helptext "Close the Dialog"
pack $base.buts.b1 $base.buts.b2 $base.buts.b3 -side left
pack $base.buts.b4 -side right
pack $base.buts -side top -fill x
pack $pw -side bottom -fill both -expand true
# This procedure is called when the user selects the File/Open
# menu option.
#
set lastDir [pwd]
if { [package provide Pan] != "" } {
pan bind $tree.c
# option -cursor is not implemented in html & html3widget...
pan bind [winfo parent [$hwidget get_htmlwidget]]
}
bind [$hwidget get_htmlwidget] <3> \
[list tk_popup $base.buts.b3.m %X %Y]
focus $hwidget
bind [$hwidget get_htmlwidget] <Prior> {%W yview scroll -1 pages}
bind [$hwidget get_htmlwidget] <Next> {%W yview scroll 1 pages}
bind [$hwidget get_htmlwidget] <Home> {%W yview moveto 0}
bind [$hwidget get_htmlwidget] <End> {%W yview moveto 1}
bind [winfo toplevel $hwidget] <Alt-Left> "History::GoBackward $hwidget; break"
bind [winfo toplevel $hwidget] <Alt-Right> "History::GoForward $hwidget; break"
bind [winfo toplevel $hwidget] <F3> "focus $hwidget; HelpViewer::Search ; break"
bind [winfo toplevel $hwidget] <Control-f> "focus $hwidget; HelpViewer::SearchWindow; break"
bind [winfo toplevel $hwidget] <Alt-KeyPress-c> [list $notebook raise tree]
bind [winfo toplevel $hwidget] <Alt-KeyPress-i> [list $notebook raise search]
bind [winfo toplevel $hwidget] <Alt-KeyPress-s> [list $notebook raise search]
bind [winfo toplevel $hwidget] <Control-KeyPress-i> [list $notebook raise search]
bind [winfo toplevel $hwidget] <Control-KeyPress-s> [list $notebook raise search]
FillDir $tree root
# if an arguent was specified, read it into the HTML widget.
if {$file_or_dir != ""} {
LoadFile $hwidget $file_or_dir
}
if { $geom == "" } {
set x [expr [winfo screenwidth $base]/2-400]
set y [expr [winfo screenheight $base]/2-300]
wm geom $base 650x400+${x}+$y
} else {
wm geom $base $geom
}
update idletasks
wm deiconify $base
return $hwidget
}
bind all <MouseWheel> {
set w %W
while { $w != [winfo toplevel $w] } {
catch {
set ycomm [$w cget -yscrollcommand]
if { $ycomm != "" } {
$w yview scroll [expr int(-1*%D/36)] units
break
}
}
set w [winfo parent $w]
}
}
# -------------------------------------------------------------------------
# helpviewer_cmd.tcl
# -------------------------------------------------------------------------
# (c) 2016, Johann Oberdorfer - Engineering Support | CAD | Software
# johann.oberdorfer [at] googlemail.com
# www.johann-oberdorfer.eu
# -------------------------------------------------------------------------
# This source file is distributed under the BSD license.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the BSD License for more details.
#
# -------------------------------------------------------------------------
# Revision history:
# 17-01-21: Hans, Initial release
# -------------------------------------------------------------------------
# Purpose:
# Implements required callback commands for the tkhtml 3.0 widget
# -------------------------------------------------------------------------
package require http
# to do:
# support for:
# + hyperlinks within the same page ?
# + search highligt (see tkhtml PDF documentation)
# + frame frameset support
namespace eval HelpViewer {}
# This procedure is called when the user clicks on a hyperlink.
# See the "bind $base.h.h.x" below for the binding that invokes this
# procedure
#
proc HelpViewer::HrefBinding {hwidget x y} {
variable HelpBaseDir
set node_data [$hwidget node -index $x $y]
if { [llength $node_data] >= 2 } {
set node [lindex $node_data 0]
} else {
set node $node_data
}
# parent node is an <A> tag (maybe?)
if { [catch {set node [$node parent]} ] == 0 } {
if {[$node tag] == "a"} {
set href [string trim [$node attr -default "" href]]
if {$href ne "" && $href ne "#"} {
set fname [file join $HelpBaseDir $href]
# follow the link, if the file exists
if {[file exists $fname] } {
LoadRef $hwidget $fname 0
} else {
# LoadRef $hwidget $node 0
}
}
}
}
}
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
namespace eval History {
variable list ""
variable pos
variable menu
proc Add { name } {
variable list
variable pos
variable menu
lappend list $name
set pos [expr [llength $list]-1]
if { $pos == 0 } {
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Backward -state disabled
}
} else {
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Backward -state normal
}
}
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Forward -state disabled
}
}
proc GoHome { w } {
variable list
variable pos
variable menu
set pos 0
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Backward -state disabled
}
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Forward -state normal
}
# HelpViewer::LoadRef $w [lindex $list $pos] 0
HelpViewer::LoadRef $w [file join $HelpViewer::HelpBaseDir "index.html"] 0
}
proc GoBackward { w } {
variable list
variable pos
variable menu
incr pos -1
if { $pos == 0 } {
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Backward -state disabled
}
}
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Forward -state normal
}
HelpViewer::LoadRef $w [lindex $list $pos] 0
}
proc GoForward { w } {
variable list
variable pos
variable menu
incr pos 1
if { $pos == [expr [llength $list]-1] } {
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Forward -state disabled
}
}
if { [info exists menu] && [winfo exists $menu] } {
$menu entryconf Backward -state normal
}
HelpViewer::LoadRef $w [lindex $list $pos] 0
}
}
# -------------------------------------------------------------------------
# helpviewer_search.tcl
# -------------------------------------------------------------------------
# (c) 2016, Johann Oberdorfer - Engineering Support | CAD | Software
# johann.oberdorfer [at] googlemail.com
# www.johann-oberdorfer.eu
# -------------------------------------------------------------------------
# This source file is distributed under the BSD license.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the BSD License for more details.
#
# Credits:
# This software related on the the helpviewer application originally
# created by Ramon Ribó (RAMSAN) ramsan@cimne.upc.es.
# (http://gid.cimne.upc.es/ramsan) for his version of the
# Thank you.
#
# -------------------------------------------------------------------------
namespace eval HelpViewer {}
proc HelpViewer::IsWordGood { word otherwords } {
variable Index
variable IndexFilesTitles
if { $otherwords == "" } { return 1 }
if { ![info exists Index($word)] } { return 0 }
foreach i $Index($word) {
set file [lindex [lindex $IndexFilesTitles $i] 0]
if { [HasFileTheWord $file $otherwords] } { return 1 }
}
return 0
}
proc HelpViewer::HasFileTheWord { fname otherwords } {
variable HelpBaseDir
variable Index
variable IndexFilesTitles
variable FindWordInFileCache
set fullfile [file join $HelpBaseDir $fname]
foreach word $otherwords {
if { [info exists FindWordInFileCache($fname,$word)] } {
if { !$FindWordInFileCache($fname,$word) } {
return 0
}
continue
}
set fp [open $fullfile "r"]
set aa [read $fp]
close $fp
if { [string match -nocase *$word* $aa] } {
set FindWordInFileCache($fname,$word) 1
} else {
set FindWordInFileCache($fname,$word) 0
return 0
}
}
return 1
}
proc HelpViewer::GiveManHelpNames { word } {
if { [auto_execok man2html] == "" } { return "" }
set err [catch { exec man -aw $word } file]
if { $err } { return "" }
set words ""
foreach i [split $file \n] {
set ext [string trimleft [file ext $i] .]
if { $ext == "gz" } { set ext [string trimleft [file ext [file root $i]] .] }
if { [lsearch $words "$word (man $ext)"] == -1 } {
lappend words "$word (man $ext)"
}
}
return $words
}
proc HelpViewer::WaitState { what } {
variable tree
variable hwidget
# set parent [winfo parent $hwidget]
switch $what {
1 {
$tree configure -cursor watch
# $parent configure -cursor watch
}
0 {
$tree configure -cursor ""
# $parent configure -cursor ""
}
}
update
}
proc HelpViewer::CreateIndex {} {
variable HelpBaseDir
variable Index
variable IndexFilesTitles
variable progressbar
variable progressbarStop
variable hwidget
if { [array exists Index] } { return }
if { [file exists [file join $HelpBaseDir wordindex]] } {
set fin [open [file join $HelpBaseDir wordindex] r]
foreach "IndexFilesTitles aa" [read $fin] break
array set Index $aa
close $fin
return
}
WaitState 1
ProgressDlg $hwidget.prdg -textvariable HelpViewer::progressbarT -variable \
HelpViewer::progressbar -title "Creating search index" \
-troughcolor \#48c96f -stop Stop -command "set HelpViewer::progressbarStop 1"
set progressbar 0
set progressbarStop 0
catch { unset Index }
set files [::fileutil::findByPattern $HelpBaseDir "*.htm *.html"]
set len [llength [file split $HelpBaseDir]]
set ipos 0
set numfiles [llength $files]
set IndexFilesTitles ""
foreach i $files {
set HelpViewer::progressbar [expr int($ipos*50/$numfiles)]
set HelpViewer::progressbarT $HelpViewer::progressbar%
if { $HelpViewer::progressbarStop } {
destroy .prdg
return
}
set fin [open $i r]
set aa [read $fin]
set file [eval file join [lrange [file split $i] $len end]]
set title ""
regexp {(?i)<title>(.*?)</title>} $aa {} title
if { $title == "" } {
regexp {(?i)<h([1234])>(.*?)</h\1>} $aa {} {} title
}
lappend IndexFilesTitles [list $file $title]
set IndexPos [expr [llength $IndexFilesTitles]-1]
foreach j [regexp -inline -all -- {-?\w{3,}} $aa] {
if { [string is integer $j] || [string length $j] > 25 || [regexp {_[0-9]+$} $j] } {
continue
}
lappend Index([string tolower $j]) $IndexPos
}
close $fin
incr ipos
}
proc IndexesSortCommand { e1 e2 } {
upvar freqs freqsL
if { $freqsL($e1) > $freqsL($e2) } { return -1 }
if { $freqsL($e1) < $freqsL($e2) } { return 1 }
return 0
}
set names [array names Index]
set len [llength $names]
set ipos 0
foreach i $names {
set HelpViewer::progressbar [expr 50+int($ipos*50/$len)]
set HelpViewer::progressbarT $HelpViewer::progressbar%
if { $HelpViewer::progressbarStop } {
destroy .prdg
return
}
foreach j $Index($i) {
set title [lindex [lindex $IndexFilesTitles $j] 1]
if { [string match -nocase *$i* $title] } {
set icr 10
} else { set icr 1 }
if { ![info exists freqs($j)] } {
set freqs($j) $icr
} else { incr freqs($j) $icr }
}
# if { $i == "variable" } {
# puts "-----variable-----"
# foreach j $Index($i) {
# puts [lindex $IndexFilesTitles $j]-----$j
# }
# parray freqs
# }
set Index($i) [lrange [lsort -command HelpViewer::IndexesSortCommand [array names freqs]] \
0 4]
# if { $i == "variable" } {
# puts "-----variable-----"
# foreach j [lsort -command HelpViewer::IndexesSortCommand [array names freqs]] {
# puts [lindex $IndexFilesTitles $j]-----$j
# }
# }
unset freqs
incr ipos
}
set HelpViewer::progressbar 100
set HelpViewer::progressbarT $HelpViewer::progressbar%
destroy $hwidget.prdg
set fout [open [file join $HelpBaseDir wordindex] w]
puts -nonewline $fout [list $IndexFilesTitles [array get Index]]
close $fout
WaitState 0
}
proc HelpViewer::SearchInAllHelp {} {
variable Index
variable searchlistbox1
set word [string tolower $HelpViewer::searchstring]
CreateIndex
set HelpViewer::SearchFound ""
set HelpViewer::SearchFound2 ""
if { [string trim $word] == "" } { return }
set words [regexp -all -inline {\S+} $word]
if { [llength $words] > 1 } {
set word [lindex $words 0]
set otherwords [lrange $words 1 end]
} else { set otherwords "" }
set ipos 0
set iposgood -1
foreach i [array names Index *$word*] {
if { ![IsWordGood $i $otherwords] } { continue }
lappend HelpViewer::SearchFound $i
if { [string equal $word [lindex $i 0]] } { set iposgood $ipos }
incr ipos
}
if { $iposgood == -1 && [llength [GiveManHelpNames $HelpViewer::searchstring]] > 0 } {
lappend HelpViewer::SearchFound $HelpViewer::searchstring
set iposgood $ipos
}
if { $iposgood >= 0 } {
$searchlistbox1 selection clear 0 end
$searchlistbox1 selection set $iposgood
$searchlistbox1 see $iposgood
SearchInAllHelpL1
}
}
proc HelpViewer::SearchInAllHelpL1 {} {
variable Index
variable IndexFilesTitles
variable SearchFound2
variable SearchFound2data
variable searchlistbox1
variable searchlistbox2
set SearchFound2 ""
set SearchFound2data ""
set sels [$searchlistbox1 curselection]
if { $sels == "" } {
# bell
return
}
set words [regexp -all -inline {\S+} $HelpViewer::searchstring]
if { [llength $words] > 1 } {
set otherwords [lrange $words 1 end]
} else { set otherwords "" }
set ipos 0
set iposgood -1
set iposgoodW -1
foreach i $sels {
set word [$searchlistbox1 get $i]
if { [info exists Index($word)] } {
foreach i $Index($word) {
foreach "file title" [lindex $IndexFilesTitles $i] break
if { ![HasFileTheWord $file $otherwords] } { continue }
if { [lsearch $HelpViewer::SearchFound2 $title] != -1 } { continue }
lappend SearchFound2 $title
lappend SearchFound2data $i
if { [string match -nocase *$word* $title] } {
set W 1
foreach i $otherwords {
if { [string match -nocase *$i* $title] } { incr W }
}
if { [string match -nocase *$HelpViewer::searchstring* $title] } { incr W }
if { [string equal -nocase $HelpViewer::searchstring $title] } { incr W }
if { $W > $iposgoodW } {
set iposgood $ipos
set iposgoodW $W
}
}
incr ipos
}
}
foreach i [GiveManHelpNames $word] {
lappend SearchFound2 $i
if { $iposgood == -1 } {
set iposgood $ipos
} else { set iposgood -2 }
incr ipos
}
}
if { $iposgood < 0 && $ipos > 0 } { set iposgood 0 }
if { $iposgood >= 0 } {
focus $searchlistbox2
$searchlistbox2 selection clear 0 end
$searchlistbox2 selection set $iposgood
$searchlistbox2 see $iposgood
SearchInAllHelpL2
}
}
proc HelpViewer::SearchInAllHelpL2 {} {
variable HelpBaseDir
variable SearchFound2data
variable IndexFilesTitles
variable SearchFound2
variable hwidget
variable searchlistbox2
set sels [$searchlistbox2 curselection]
if { [llength $sels] != 1 } {
# bell
return
}
if { [regexp {(.*)\(man (.*)\)} [lindex $SearchFound2 $sels]] } {
# -removed- SearchManHelpFor $hwidget [lindex $SearchFound2 $sels]
} else {
set i [lindex $SearchFound2data $sels]
set file [file join $HelpBaseDir [lindex [lindex $IndexFilesTitles $i] 0]]
LoadFile $hwidget $file 1
$hwidget showSearchWidget
# without delay, html widget 'll potentially crash!
after idle "$hwidget setsearchstring $HelpViewer::searchstring"
}
}
proc HelpViewer::Search {} {
variable hwidget
if { ![info exists ::HelpViewer::searchstring] } {
set msg "Before using 'Continue search', use 'Search'"
append msg [winfo toplevel $hwidget]
tk_messageBox \
-icon warning -message $msg \
-type ok
return
}
if { $HelpViewer::searchstring == "" } {
return
}
$hwidget showSearchWidget
# handing over the search command to the
# html3widget (which has a build in search capability)
# note: without delay, html widget 'll potentially crash!
after idle "$hwidget setsearchstring $HelpViewer::searchstring"
}
proc HelpViewer::SearchCmd {} {
#
# perform search as well on the html viewer widget content
# search up to the 1st occurance of the search string
# so that the string item is highlighted and immediately shown
# on the screen...
#
variable searchstring
if {$searchstring == ""} {
return
}
# html widget needs some time to establish screen...
# catch maybe not really required, just in case...
after 400 "catch {[namespace current]::Search}"
}
proc HelpViewer::SearchWindow {} {
variable hwidget
$hwidget showSearchWidget
}
# ImageLib.tcl ---
# Automatically created by: CreateImageLib.tcl
set images(emblem-unreadable) [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI
WXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAWAAAAFgDcxelYAAADlElEQVQ4y9WUTWwbRRTH/961
x+D9aDmWjxskNE1UEEgcGojghtRISImEBKUF6sbBadU7Rv5SnKByQGrJVzFJDCrqwQfUcuCAaEr4
uCDamOTSCy1ULYVmv7xe787a+zjURkmJ2yIkJEZ60szoP7958968B/xXI5tN9adzbz//b7XCxkU6
lxoUwuJyWAx/lc6lBu8EvWdtOpcaLEzmPKfukOM4VJjMeZ0OtLV2zSa7ZnfWpnOpofx4mup1h4Ig
oCAIyLTMLQ+0obqhEececc7JtquUH09TNvvOC5tCIVBIBwAiACBwn0OSJBxOHmVRxspteDqXGowy
Vk6+dYTFYhKqNQsE+uvSIEQPtOehjZ5EGSsfTh5lkiTD4x6ijMG2bUzNHOc+56UIYweSo0dYTJJQ
tS3IkgKnVsP03AnOuT+czxTO3jHOhmmQ3/Cpalvk+5x0Q6OJd/Ok6Rp53KWb2u/kei5p2jqNT2a9
uyV6M9zQifucDFMnz3MpCAJyPZf+WL9Brle/K1S8feP80vKl/uf2rPx44YehJ3Y/Kcbuj6Fas+DU
a/BcF4qkwnEczMx+wLnf+fnCVpv5TOGsz3lpeuYEIhGGIAhuGQVgLIrZ2Sk0fL/UMaZbedwOB2Ns
YnRkTBSEEFyvDiICEUEURfT29uHixQt9/QN7Vs4vLV+6J3D7d4wcSjJJlmDZJmRZhapsgyiIMC0d
iqKgp6dX/KmyMtQJ/reSjkYi5UPxUSZJMZiWATmmoGpZOPbeBCzLgqpsg2asQ5IkvLb/dcbCkfJW
CRRvh8YPJpgsy7BsE4qkwjRNzM9/yBu+P1+prPR1dz8uqooK3VyHqqjo6uoW19ZWh54d6N/kudCC
DoUF8UwiMcZkRYFVNSHHFOiGgYWFIucNfzibKYzwhj9c+niB64YOVdkOTb8JRVGwb99+JgrCmY4l
3QyaICJIMRm6oWNxsch103g1nymcAyDnM4VzVrX6yqlTn3BN06Aq2xEEAZqNJoDNJS0CwNLS1788
/cxTldXVyks9PbtE7nEsLhb9a9dvHDz+/tSXABiA+wCI333z/eWdu3auXbny895HH+sSPdfF6dOf
8mrNfnly/NhnwK3mEQIQBhAFEE0k43sf3LGjBAC/Xr36ZnFu4QsAfsuaLUciAMLxxBsvPvLQw/MA
cO236wfmpoufA/Ba1mg3oUgLHk6MxQfIp8bJkx99C6DREvobEv5PtP+j8Sc0NB687S7VUwAAACV0
RVh0Y3JlYXRlLWRhdGUAMjAwOS0xMS0xNVQyMzowNDowOS0wNzowMOh51zsAAAAldEVYdGRhdGU6
Y3JlYXRlADIwMTAtMDEtMTFUMDk6MDk6MjYtMDc6MDCVrk2EAAAAJXRFWHRkYXRlOm1vZGlmeQAy
MDEwLTAxLTExVDA5OjA5OjI2LTA3OjAw5PP1OAAAADR0RVh0TGljZW5zZQBodHRwOi8vY3JlYXRp
dmVjb21tb25zLm9yZy9saWNlbnNlcy9HUEwvMi4wL2xqBqgAAAAldEVYdG1vZGlmeS1kYXRlADIw
MDktMTEtMTVUMjM6MDQ6MDktMDc6MDC3yKEPAAAAF3RFWHRTb3VyY2UAR05PTUUgSWNvbiBUaGVt
ZcH5JmkAAAAgdEVYdFNvdXJjZV9VUkwAaHR0cDovL2FydC5nbm9tZS5vcmcvMuSReQAAAABJRU5E
rkJggg==
}]
set images(system-search) [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI
WXMAAA3XAAAN1wFCKJt4AAAACXZwQWcAAAAWAAAAFgDcxelYAAAEVElEQVQ4y7WT209UVxTGv3Xm
DsMwcxhgRIyDVkGMZYy1aRWiVaJtkJvpQ31pbN/atA99aI1RmxBNGPGlf0ANSU1No6maam1VRlCw
iSi1tNXCjBEGGS7OgbngzDlnzpy9++BgjC3oiyv5spK9d35r5dtrEeccryKEV0IFYPyfM2rvONJI
oPcA1HNAJGAcoFEOdnz/Vwd/ehkwPWuF3+93QdC/q6yq2rVxw0aIohtWqxWKLCMWn8WNG714MDJy
nTj7bN++Q3+9FNjv93sFA+9uam72rqhYhfN9w/HuwWn9XnjWsdYrJt+pKTXs2lzpDIcf4Oy5s5Jm
0H0HvjgQebHHBv2b1tbdXrGojLUcupC8GUrO7qqrShz9dNtY7fqV0Yu/Rx81H7yQKBQ9rKmxyW3Q
8ENbW5txIbARANqPtddVLK9oLi9fjtavL87t2fH6RP36pUVmo2DSdKa57JZM5TKX8mPfg+G9Hd1V
5w43OFavXl07HAzuAXBiwY6Js899Ph86f74TXVrqnN5U7bEDHAycA2CCQFmDAFbkzIszMjw8Fbgb
q6nxgYjvWNQKAlYaTUZ03XnE3qgskzWdZRVNl1WNxTXGEpzzpJbVZ6YTmdHSYuf4L7cnsjabDZxh
66JWcGAZYzrGpZRotZpG5EzWxMmgMQgZ4iyjM6j992O3NT2bsedbDAP3I9uzWQ2qmsl70RwrRqMJ
Ze78mVAkwVctdSSJSIaeVTKMRW8FZ/qDE6k0BIiJOWWZaDfNJpPJEjWjPlwczBGQ0/Leel+J4cLt
iEMwGXvFAlsildbGY3I2TAJ/LBBcnME6NR2r2FlTDFVVoanK2OLjJuDXoaF/8FFDjZvrWvnoRKwk
MpuaiymqDAACezLs4QnpNUHX1n/csK7kZn8/VEX9ftGOxcLiM6FQ6Lfq6pFNJ/Zvs3/o79429She
XFLkuGUvsFji8bQrKiXfthr5lhMHttuj0UkMDg5mhoaDsRdu3rFjbR5OloGW5pYyr3clzvcFZ3v+
nNbvjs441y53xbf6PKbGzZXO4eA9dHZ2Ih6PQ5KktMVkazh9+nTPgmAAOHr08DpGwrcrvBVv1tbW
weUUYbXZoMgypBkJPT3duN7bq2QzGWvVmjUoK1uCrq5AStHSTadOnrm6IHg+2juO7CZOn0BAOThK
VVVNyLIaUNT0pUuX++J2u+1cc+O7eUs8HpjMZgQCgZSsplpPnTxzZVHw00ui+Q+mnAAA1Rs2vCU6
HBd31m8p8HiWwGKxoKurKyWrqaedC8+BDERkJiIbEeUDcORUCMA5r3sDA0NTk9H3L1/peTw5NQlV
VVFXV5cvwHiciIxEREIOSERkAmAGYMnJBiAPQD6AglwBJwAXgML7Q38HxyKRDy5fuTYXHgtDkqLQ
s7rT7XbbAJjnN48vIJazQH/m3Xxm4VDoDzCh5WrPjQ6bxVwuCPhSkiQdgP4fj+mJscIzMjyXkSuo
P5fnxTnn+BdfFBTdhrqWWgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMC0wMS0xMVQwOToxMzowMy0w
NzowMFMfKlcAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTAtMDEtMTFUMDk6MTM6MDMtMDc6MDAiQpLr
AAAANHRFWHRMaWNlbnNlAGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL0dQTC8y
LjAvbGoGqAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAATdEVYdFNvdXJj
ZQBHTk9NRS1Db2xvcnOqmUTiAAAAMXRFWHRTb3VyY2VfVVJMAGh0dHA6Ly9jb2RlLmdvb2dsZS5j
b20vcC9nbm9tZS1jb2xvcnMvUB216wAAAABJRU5ErkJggg==
}]
set images(go-home-4) [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI
WXMAAA3XAAAN1wFCKJt4AAAACXZwQWcAAAAWAAAAFgDcxelYAAADKElEQVQ4y6WUwWsUVxzHP+9l
ZuKu2e6YTVrXUncpSA0VqUhqwEsPbVok6MIiCW1K/oI9yUip2H9gKKiRerJNaQ4prTAb8OLZg4ce
apraQ0PrIWyCSXZjm3XX7My8HmZ2nDVuEugPHjPzfu/3+f3e9/3eCPZhs5AFKuHnqUn4dT9xe0FP
z4Lasiy1ZVlqFlSYaFcTe0GBXwqW1THv2DbAkUlY6RYr9wN9ev9+NF+dnydMVNmtcrkXtPnwIX2Z
TId/P3CxG9RdWkJqGjKfb2+fgmWxXi4jhaD//PmusshuUFWpIFOpCPrH2DmWP53AsW0GLlzAVWrX
ykUMOgn8ULAsVK0WOA8dwrFt6p9/xtrxd3jj9cMcq22yfPkyBctitVzG6FJ5HKwKlgWNBmxvQzqN
Y9s8ty7xz5tHGBp6l2QiQbPZJLmyyuOpqQDuOBhSRvDJkKmF0APtBKrRQPT349g26msbmcnwXi5P
LpcL/Aq23zqKfvcuc8UiE6USq46z4/C08JmMtAmhPd/dxtV0zp4ZwTTNKEApBYBpmmQePGBuZISJ
Umnvdrt252e8mW9paRrDw+/T19eH53kdo9Vq4XkevZkMo48eMTc9HW8A2aHxvZMnp54sLMycWfqT
L698saOCmze+wfd9rl2fRokelNtEaAdQ3nO+unqVcirFwIkTpU8WF2/GpWB0YeH7i+PFmXP9wWUY
GjqOEAIhgtye56GUQglJT34Ud2kekfsI9fgeSinK40XyR9++xeLiq6Voa2gYBrquo2kauq7j+34E
r2xsAfDbX+t4nh/F2LatXqWxFgdLKZFSYshlNFHF931838fF4Pe/NwB4UnuGK3qjGILuetFuQA9w
MA5uS+CTpdEMoNlslg/ODvNx4iBSHeZDqbO2QhycIbggrhZm0LqBoZdEAnzfB+BpbR2xudEhX7Va
jbr15T4WbVkMw8A0TdLpNAJJwBcMDg5Sr9cZGxvb0THJZHQN6oBqA0UoRerieLHK/7CffryjA268
9LYcveEBvBbqNQAkQp8Xrt0K31vAJvAvsAY8i63p+B/Hk8jwqcd2RSxQhcMLh+Il+w9pZlYolc7x
lgAAACV0RVh0Y3JlYXRlLWRhdGUAMjAwOS0xMS0xMFQxOTozODoyMC0wNzowMIB9jfEAAAAldEVY
dGRhdGU6Y3JlYXRlADIwMTAtMDItMjBUMjM6MjY6MTUtMDc6MDAGO1yBAAAAJXRFWHRkYXRlOm1v
ZGlmeQAyMDEwLTAxLTExVDA4OjU2OjMwLTA3OjAwFkPu1gAAADJ0RVh0TGljZW5zZQBodHRwOi8v
ZW4ud2lraXBlZGlhLm9yZy93aWtpL1B1YmxpY19kb21haW4//erPAAAAJXRFWHRtb2RpZnktZGF0
ZQAyMDA5LTExLTEwVDE5OjM4OjIwLTA3OjAw38z7xQAAABl0RVh0U291cmNlAFRhbmdvIEljb24g
TGlicmFyeVTP7YIAAAA6dEVYdFNvdXJjZV9VUkwAaHR0cDovL3RhbmdvLmZyZWVkZXNrdG9wLm9y
Zy9UYW5nb19JY29uX0xpYnJhcnm8yK3WAAAAAElFTkSuQmCC
}]
set images(draw-arrow-back) [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAFzUkdC
AK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dE
AAAAAAAA+UO7fwAAAAlwSFlzAAAEwgAABMIBvM+QGAAAAAl2cEFnAAAAFgAAABYA3MXpWAAAAoZJ
REFUOMvFlE1PE1EUht/7MXPpQCgk7FyRuGBhDIk7ygaBIAlYQ0lMZIFsXJu45i/oDzAp6AIChWKR
poLQBKQkYqOucIk/gDCQEGYa597jojAWqB8NTXw3dzLnnmfec+fcA/wvTU5Oh89EVD9wsfg1trv7
+VOx+OVpLXn8T8FC4WPP6am/3dbWesf3Sy/qAs7nt+56np9vb79B0Wgz8/1STZVWBedyG72e5290
dNykSCTCOOcola4JXl7O9vq+t97ZeYscJ8IYY+CcoxbHi4uLYJUvUqlMrzF6vaenmyKRCNNag4hg
WRILC29JKbtiP7vQJWUDDFLKl4nE/SfhxpmZVJ/W+v3Q0AA5jsOMMdBaQ2sNYwwsywKRARHBGIIQ
Ak1NTSH44OAAWmusruYxPv6ISQBIJl/3e97p2sjIA2ppaWbGGBhjwBgDYwzGGARBcAY1UEqhsbER
RAQiwsnJCYIggJQy/BdyampaGIO1RCJO0WgzAwDOeQjlnENrHa6O48C2bQDlCxMEAUqlEoQQEIID
KB8Pn5h4rIUoJ1WKMQYhBKSUkFJCCHEBer7H87zQCOccQohfXWFZVvfKyjt2eOhWvbNCCNi2HSad
uz0/Ms75GfwSeGzsYUEpGcvl1pjrHtFl55Xr5YoaGhqglIJSKqys3DMVmptb6jLmR2FgoJ9aW1su
xJLJV6SUYtU+UCnbtp6Pjo48u1L20lKma34+Ta7rGqrQ7Oz8P4+2dDpdPZDJZLrS6TfkukchPJVK
1zQzq86KeDy+Y1kqtrn5gR0fHxMASClq4f5+ug0PD+4oZcW2trbZ/v53EkKauoABYHDw3o6U8vbe
3rdZy5J9NVn+m7LZbF1519ZPBq0o6tkbPl8AAAAldEVYdGNyZWF0ZS1kYXRlADIwMDktMTEtMTVU
MTc6MDM6MDUtMDc6MDBx3el7AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEwLTAxLTExVDA5OjI1OjI2
LTA3OjAw1/4UywAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMC0wMS0xMVQwOToyNToyNi0wNzowMKaj
rHcAAABndEVYdExpY2Vuc2UAaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkt
c2EvMy4wLyBvciBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9MR1BMLzIuMS9b
jzxjAAAAJXRFWHRtb2RpZnktZGF0ZQAyMDA5LTA2LTI0VDEwOjM2OjQ3LTA2OjAwVRY2/AAAABN0
RVh0U291cmNlAE94eWdlbiBJY29uc+wYrugAAAAndEVYdFNvdXJjZV9VUkwAaHR0cDovL3d3dy5v
eHlnZW4taWNvbnMub3JnL+83qssAAAAASUVORK5CYII=
}]
set images(dialog-close) [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI
WXMAAA3XAAAN1wFCKJt4AAAACXZwQWcAAAAWAAAAFgDcxelYAAADzklEQVQ4y7WVPU8bWRSG3zvj
Gdt3bMM62J5gZ+NAA6JIEykSCRnbVDRUW/AHtt9i22i77fIX0i7FVtNsEwWPSIpIaYIUFCmKQgJs
GBuDPR4PHs/92MI2C9gpc6Wj+dB7nnvmPfdoiJQSP2IpP4QKIHbzRb1ajWmdzjYARDMzW5WdHTYt
sV6txjTP24aUU3XKTTE5O7MT+fxGolDYUM7O7Hq1OnVzpd22E6a5kSgUNsgUnXIN2mrZqUKhUqpW
aWl9nRrz8xXSal1LGusM06zcqdVoaX2dpkxzQkfGzdtZWfnbyOU2fq7VKDs/B1EUqLkcjl6+vPCO
j+tKPr8JAGg07FSpVCnVaknebAJSQs1mcfjiReA3Gv9U37//5brHQgBCQEQR5Dg4R3FtLSkdx+oe
HdkAkC6VrNLaWpKdnED2+yCaBjEYQHI+ZNy0gpjmVsd1nUPHCdRMBlAUCN8Hc12UVldpulh8ki4W
n5RWVylzXQjfBxQFSjqNw52doOO6DjHNrQkrAKBOSCxaWLBThYJ159EjKtptIIpAdB1qNgsA4Ofn
kGEIoutQZmfx9fXrwHddR/v0abMiJZsKHsPDcnkIf/iQCs+DjCIQTQOA4b2uDyt98ybwXdeJHxxc
g04Fj+EXd+/amUJhrfjgQYq32wDnw4RYDMrMDI7fvvU9191NfvkyAZ06IOMlGYNgDHwwAI+i/8FC
QA4GEIxBMva99OlW+Ldv28atW9b8/ftUBAHAOYiqDjfkHCQWA0km8e+7d0Gv1XJS375NVK3chHbz
eTuRyVj5pSUaeR54vw8hJaSmQWoahJRgFxdgnof88jJNZDJWN5+364TEplZcJyTmzc3ZidlZy1xe
pnJ0NhVVBUkk0PjwwQeA/NJSSobh0AZVBYnHcbK/H/TbbSdzenpZ+WXF7Wx2WzcMa+7ePcp8H6zf
hxQCHMDx3l7QbTZ3u83m7vHeXsClhBACPAzBul3kFhaobhhWO5vdnmieEAKcMfAwhBQChBBIAM2P
H4O+5zk/dTqbAHDOuX2yv2/lFhepHDUUnEMwBjF+vmnFaTptxw3DypXLlBCC5sFB0Pd9Z67bvfzE
sS6RSlm5cpkCQOPz5yDs9a7pJiavSakdNwwLAC56vVd/BsHWHiAAkPFJXAHUp5T+lTSMxwAw6PWc
uSCYPnmEEB2AvgjQP+Lx5wJQfg/D304BdWSZOoILADwLiGfx+DMFEE/D8NevQABgAGAgpWRXwSoA
HUB8dNUBaFdCvVI1BxBdiQGA/igiKaUg3/uZEkLICERGp+fSiishAEBOgfwHrlwiLshhIVcAAAAl
dEVYdGRhdGU6Y3JlYXRlADIwMTAtMDItMTdUMDc6MDM6MzMtMDc6MDAWPxGJAAAAJXRFWHRkYXRl
Om1vZGlmeQAyMDEwLTAxLTExVDA5OjEzOjAxLTA3OjAwtd2DwgAAADR0RVh0TGljZW5zZQBodHRw
Oi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9HUEwvMi4wL2xqBqgAAAAZdEVYdFNvZnR3
YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAE3RFWHRTb3VyY2UAR05PTUUtQ29sb3JzqplE4gAA
ADF0RVh0U291cmNlX1VSTABodHRwOi8vY29kZS5nb29nbGUuY29tL3AvZ25vbWUtY29sb3JzL1Ad
tesAAAAASUVORK5CYII=
}]
set images(draw-arrow-forward) [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAFzUkdC
AK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dE
AAAAAAAA+UO7fwAAAAlwSFlzAAAEwgAABMIBvM+QGAAAAAl2cEFnAAAAFgAAABYA3MXpWAAAAmdJ
REFUOMvFlM9LVFEUx7/n/qKZYTQCpYWbFu4DN26aAjFREReO4UJI3LVo2x/RskU7ESGVGt8QY+YY
uZgeGjhQbbSl/Qk2KO/n3NNC32OMycYy+sLj3gvf8znn3nPfBf63mPnfwev1L4/39j7V6/XPhd95
xWXAQeA/y+ezA74f1HZ2Pg5fIThAJnONentvsOeF77a33ftXBA5BRDBGU1/fTQ4Cf6tafd8WLhzH
6Rjs+z6MMVBKIZvNUH//LY6ieKtS2Rz52UsAsLZWeR5F8SPAXoAlhGHAY2PDFEURhBDo6elBGEa8
sbFFAEaLxcnqOfDS0goXi5Ngtji9Vdx2ZGaEYQRjNLq7u9OUYRiy41SIGaOzsw+q6Rl7ng+lJKxl
WGvRbFo0m810jOPm2bqJXC6LfD4Pay2YGcwMpRQNDg5wEHibCwsvRluax9DawBgDrTWUUtBaQ0qZ
fkSEXC4HY0wKtfb06I6Pj9HV1UVDQ/cYsG8XFxeMAgClBIgIWus0IKkmmUspIcRpHUQEZgYRpTuR
Up75BOL4eqQAQAiVBgghUlNrVQksbQ4RACCOY0gp0Wg02HV3SWtzd25uis8qlufMyTxJ1KokUZJE
CAHP89l1d8kYXZiZmXYBQAFAJpN5urLy8slFd5iZEQQBz88/pFbwyckJ12ouGaML09NTbhqwvPym
4x9kdfUVt+ro6MiWSmV2nMqdjiHtVCqVW6Dfbbn8miuV9bZQdRlw0otGo8G12gfS2hQmJsbcvwZL
qYLDw29mf/+AlDKF8fER91feS71uSqmRg4Ovq0LI2xdB/1jr65tXzuxYPwBSLVS8t8W5kAAAACV0
RVh0Y3JlYXRlLWRhdGUAMjAwOS0xMS0xNVQxNzowMzowNS0wNzowMHHd6XsAAAAldEVYdGRhdGU6
Y3JlYXRlADIwMTAtMDEtMTFUMDk6MjU6MzUtMDc6MDAqvA7IAAAAJXRFWHRkYXRlOm1vZGlmeQAy
MDEwLTAxLTExVDA5OjI1OjM1LTA3OjAwW+G2dAAAAGd0RVh0TGljZW5zZQBodHRwOi8vY3JlYXRp
dmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8zLjAvIG9yIGh0dHA6Ly9jcmVhdGl2ZWNvbW1v
bnMub3JnL2xpY2Vuc2VzL0xHUEwvMi4xL1uPPGMAAAAldEVYdG1vZGlmeS1kYXRlADIwMDktMDYt
MjRUMTA6MzY6NDctMDY6MDBVFjb8AAAAE3RFWHRTb3VyY2UAT3h5Z2VuIEljb25z7Biu6AAAACd0
RVh0U291cmNlX1VSTABodHRwOi8vd3d3Lm94eWdlbi1pY29ucy5vcmcv7zeqywAAAABJRU5ErkJg
gg==
}]
# do something like:
# where to find the required library packages...
set auto_path [linsert $auto_path 0 [file join $::starkit::topdir "lib"]]
package require Tk
wm withdraw .
package require tile
# package require Img
package require http
# requiring exactly 3.0 preferable a download from Activestate
package require -exact Tkhtml 3.0
# same is required for BWidget ...
package require -exact BWidget 1.9.10
package require BWidget_patch
Widget::theme 1
package require helpviewer 3.0
# ------------------------
# start the help viewer...
# ------------------------
set help_dir "where_to_find_the_html_documentation"
HelpViewer::HelpWindow $help_dir