[JOB] 17-02-11 Yes, Tkhtml 3.0 is still alive ! [WikiDbImage HelpViewer3.0.png] 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 ** 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: * The [getfileordirectory dialog] has been implemented since version 3.0.2. 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 ====== # ------------------------------------------------------------------------- # 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)]*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 "HelpViewer::Select $tree 1" $tree bindText "HelpViewer::Select $tree 2" $tree bindImage "HelpViewer::Select $tree 1" $tree bindImage "HelpViewer::Select $tree 2" $tree bindText "HelpViewer::Select $tree 3" $tree bindImage "HelpViewer::Select $tree 3" $tree bindText "HelpViewer::Select $tree 4" $tree bindImage "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 "HelpViewer::Select $tree 1 {}" bind $tree.c "if \[string is wordchar -strict {%A}\] {HelpViewer::KeyPress %A}" bind $tree.c "" bind $tree.c "" bind $tree.c { 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 "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 "if { \[%W curselection\] == {} } { %W selection set 0 }" bind $searchlistbox1 "focus $f2.lf2.lb; HelpViewer::SearchInAllHelpL1; HelpViewer::SearchCmd" bind $searchlistbox1 "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 "if { \[%W curselection\] == {} } { %W selection set 0 }" bind $searchlistbox2 "HelpViewer::SearchInAllHelpL2; HelpViewer::SearchCmd" bind $searchlistbox2 "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] {%W yview scroll -1 pages} bind [$hwidget get_htmlwidget] {%W yview scroll 1 pages} bind [$hwidget get_htmlwidget] {%W yview moveto 0} bind [$hwidget get_htmlwidget] {%W yview moveto 1} bind [winfo toplevel $hwidget] "History::GoBackward $hwidget; break" bind [winfo toplevel $hwidget] "History::GoForward $hwidget; break" bind [winfo toplevel $hwidget] "focus $hwidget; HelpViewer::Search ; break" bind [winfo toplevel $hwidget] "focus $hwidget; HelpViewer::SearchWindow; break" bind [winfo toplevel $hwidget] [list $notebook raise tree] bind [winfo toplevel $hwidget] [list $notebook raise search] bind [winfo toplevel $hwidget] [list $notebook raise search] bind [winfo toplevel $hwidget] [list $notebook raise search] bind [winfo toplevel $hwidget] [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 } ====== * helpviewer_bindings.tcl ====== bind all { 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 ====== # ------------------------------------------------------------------------- # 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 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 } } } } } ====== * helpviewer_history.tcl ====== # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- 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 ====== # ------------------------------------------------------------------------- # 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)(.*?)} $aa {} title if { $title == "" } { regexp {(?i)(.*?)} $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 } ====== * hvimages.tcl ====== # 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== }] ====== * Demo: ====== # 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 ====== <>Category GUI | Category Object Orientation | Category Widget | Category HTML