Tuesday, May 20, 2014

sesion interactiva: tablelist

Empecemos con checar cuantos "hijos" tiene la ventana principal, llamada "."
% winfo children
wrong # args: should be "winfo children window"
Me falló porque faltó un parámetro

% winfo children .
No me regresa nada, es que aun no le pongo controles a esta ventana


% proc tl {} {};edit tl
Edito (en otra ventana) un proc que crea una tablelist accesible con la variable "tbl"

proc tl {} {
global tbl
set tbl .tbl
tablelist::tablelist $tbl\
  -columns {0 "A" 0 "B" 0 "C" 0 "D" 0 "E"} -height 15 -width 100
pack $tbl
}

Creo un botón
% button .btn -text rengSel?
.btn
% pack button
wrong # args: should be "pack option arg ?arg ...?"
Me fallo' porque no hay botón llamado "button" (se llama .btn)

% pack .btn
Ahora si aparece botón en la ventana

% tl
invalid command name "tablelist::tablelist"
Falla porque no puse la "incorporación" de la librería en el proc...

Ahora si lo hago...
% package require tablelist
5.7

% tl
Ahora si aparece la tabla en la ventana (pero tuve que hacer un "resize" manual)

Le hago ediciones para que se le inserten renglones a partir de la lista de "hijos" de "."
% edit tl

Cuales son los "hijos" de "." ?
% winfo children .
.btn .__helpLabel .tbl .tbl-corner

Le inserto los hijos
% $tbl insert end [winfo children .]
k0
Pero me aparecen en un solo renglón...eso no es lo que quería...

"." tiene 4 hijos...
% llength [winfo children .]
4

Veamos esos 4 "hijos"
% foreach ctrl [winfo children .] {
puts $ctrl
}
.btn
.__helpLabel
.tbl
.tbl-corner

Quiero borrar el renglón...
% $tbl delete all
bad row index "all": must be active, anchor, end, top, bottom, @x,y, a number, a full key, or a name
Falla porque "all" no es un indice válido

% $tbl delete 0 end
Ahora si se borró

Le inserto un renglón por cada "hijo"
% foreach ctrl [winfo children .] {
$tbl insert $ctrl
}
bad row index ".btn": must be active, anchor, end, top, bottom, @x,y, a number, a full key, or a name
Falla porque me faltó poner donde insertar

Ahora si...
% foreach ctrl [winfo children .] {
$tbl insert end $ctrl
}

Al tener seleccionado el primer renglón, el comando "curselection" indica cual es la selección actual:
(numeración empieza en cero)
% $tbl curselection
0


Al tener seleccionado el renglón 2:
% $tbl curselection
1

Al tener seleccionado el renglón 3:
% $tbl curselection
2

Al tener seleccionado el renglón 4:
% $tbl curselection
3

Para obtener el valor de una de las celdas:
% $tbl cellcget 1,1 -text
No devuelve nada porque no hay nada en segunda columna, (recuerde, numeración empieza en cero)

Ah, entonces es así:
% $tbl cellcget 1,0 -text
.__helpLabel

Para obtener el valor en celda de:
renglón   =  la selección actual
columna  = 0 (numeración empieza en cero)
y estando seleccionado el renglon cuyo contenido de texto es "tbl-corner"
% $tbl cellcget [$tbl curselection],0 -text
.tbl-corner

Asignarle una acción a botón existente
% .btn configure -command {puts [$tbl cellcget [$tbl curselection],0 -text]}

Al hacer click en el botón...
.tbl-corner



Luego selecciono el tercer renglón en la tabla...y hacer click en botón
.tbl
(ya que ese es el contenido de esa celda)

Monday, May 19, 2014

editando con tkcon

 La instalación de ActiveTcl viene con una consola mejorada (tkcon), la cual, por ejemplo, te puede servir para editar de mejor manera cuando estés trabajando de manera interactiva:



En el "pantallazo", puedes ver como se crea un nuevo proc, para ser editado de inmediato, con el comando edit.
El comando "edit" te permite editar ese proc en ventana nueva y desde la cual puedes:
a) salvar ese proc en un archivo nuevo (menú "File" >>> "Save As...")
b) agregarlo a un archivo existente (menú "File" >>> "Append To...")
c) y/o enviarlo a la consola en la que estas trabajando (menú "Send To..." y seleccionando la opcion "Send To slave", que de hecho es la única opción que viene bajo ese menú)


si cierras la ventana de edición, puedes re-editar ese proc, tecleando:
edit sampleProc

Por cierto, la opción "Append To", te pregunta si deseas sobre-escribir el archivo, lo cual puede crear alguna confusión ya que realmente no lo sobre-escribe, solo lo agrega, tal como lo indica la opción seleccionada.

te invito a usar esta prestación de tkcon como herramienta de desarrollo!

Tuesday, May 13, 2014

jugando a multiplicar

El ejemplo de hoy es excelente para confirmar el porque Tcl/Tk es:
"El poder de lo simple!"



Script: A little multiplication toy



Este script tiene únicamente 2 procedimientos ("main" y "recompute") y tiene como característica interesante el hecho de que no hay que presionar algún botón para calcular el total de la multiplicación de los 2 números que se hayan capturado, sino que se va calculando automáticamente según se vayan "entrando" los factores.

* Vea como es que ".*" y ".=" son nombres validos para controles en la ventana principal.
* las cajas de captura (entry) están asociadas a las variables a y b
* el comando "trace variable" es el que hace posible que, un procedimiento sea ejecutado cada vez que se escribe (w = write) en dicha variable.
* el procedimiento en cuestión es "recompute" el cual simplemente calcula el valor de c como el resultado de la multiplicación. Esto ocurre en cada cambio que se hace en las cajas de texto/captura.
* se hace un manejo de errores con catch por si uno de los factores es aun inexistente o se le introduce algo que produce un error
* Para finalizar, y a manera de "bonus", se recomienda apreciar la técnica de hacer un pack de todos los "hijos" de ".", a través de los comandos "eval" y "winfo children"

hasta el próximo "post" !

Sunday, May 11, 2014

Eventos en el canvas

Hoy, continuaré comentando el código de "i-Map and indexed map viewer", en esta ocasión enfocado en como asociar acciones en respuesta a eventos ocurridos.
El comando usado para esta tarea es:

bind

Veamos el siguiente código:



Subrayado en rojo:
la opción -modifycmd del control ComboBox se usa para definir que procedimiento ejecutar cuanto el valor seleccionado cambie, es decir, cuando el usuario haga una nueva selección.

La sección marcada con azul, muestra como asociar el desplazamiento de la vista del canvas en respuesta a que las teclas arriba,abajo,izquierda y derecha (Up,Down,Left,Right) sean presionadas.

También se muestra, resaltado en amarillo, como asociar un click sobre el canvas con el cambio de texto en el titulo de la aplicación, en base a las coordenadas x,y de la posición del mouse al momento del click.

Acerca de esta otra sección de código:



Ya que se hizo este programa para poder ser ejecutado en una PocketPC (tomar en cuenta que este código se publicó en 2003!), se hicieron asociaciones para que los triángulos dibujados en el canvas, apuntando en cuatro direcciones, generaran eventos como si fueran las teclas arriba,abajo,izquierda y derecha.

Subrayado en azul, se resalta la sección que, uno a uno, define la generación de eventos ante un click en esos triángulos, durante su creación, los identificadores únicos se han asignado a variables cuyo nombre nos recuerda la dirección a la que apuntan.

hasta el próximo script!

Saturday, May 10, 2014

Resaltando lugares en mapas

En esta ocasión voy a comentar el código "iMap: an indexed map viewer", el cual puede verse completo en:
http://wiki.tcl.tk/8771

Este ejemplo, toma un mapa (archivo gif el cual debe ser previamente descargado de http://www.bioenergywiki.net/images/thumb/7/71/Uk-map.gif/300px-Uk-map.gif)

Desde luego, el archivo debe ser renombrado a UK_Map.gif para que no falle así:



Pues bien, el funcionamientos de este programa es como sigue:
* Al seleccionar algún lugar en el "combo box", la región de interés es desplazada al área visible y un cuadro rojo aparece y desaparece resaltando el punto exacto.

* Hay cuatro triángulos apuntando a los cuatro puntos cardinales a los cuales se les puede hacer click para mover la vista del mapa en esa dirección.

* Adicionalmente, si se hace click en algún punto del mapa, la ubicación x,y de dicho punto se muestra en la barra de titulo de la aplicación.



Comentando el código:
1) Marcado en amarillo, vea como se toman los datos x,y del arreglo "data", el cual fue previamente cargado con el proc "index:"
2) Subrayado en azul, se toma solo el segundo para de coordenadas de la región completa del mapa (se recomienda estudiar el comando bbox del canvas) y junto con las coordenadas del punto de interés, se mueve (xview/yview moveto) la "vista" del canvas a la región que resulte de los cálculos.
3) El efecto de "flash" del cuadro rojo, se logra con el almacenamiento del identificador único de dicho cuadro, en la variable "id" (subrayada en rojo) para que, a través de ese "id", la propiedad "width" de las lineas que lo forman,pueda ser alternada en 5 y 0, lo cual hace el efecto de desaparacer tras 300,600 y 900 milisegundos.

En la siguiente publicación, seguiré comentando otra sección de este mismo código que puede resultar de interés para el principiante.

Thursday, May 8, 2014

checkbuttons

En esta ocasión, veremos como usar las opciones que hayan sido seleccionadas en los llamados checkbuttons.
Tomaremos de ejemplo el script "A symmetric doodler", creado por Richard Suchenwirth y disponible en http://wiki.tcl.tk/2859

El estudio de la sección de interés sera apoyada por el siguiente diagrama:



1) El comando bind define cual procedimiento será ejecutado cuando el evento click (el cual se escribe como <1>), suceda en la ventana $w, la cual, en este caso, le es asignado el canvas:
symdoodle [canvas .c -height $size -width $size -bg $bg]

2) Antes de hacer los trazos en el canvas, se corre el proc "readCheckbuttons"

3) El proc "readCheckbuttons" hace uso de la técnica de usar una sola variable (un arreglo) para los valores globales, en este caso:
g(hori)
g(vert)
afectan el flujo de ejecución, lo cual es lo esperado.

4) Los indices "hori" y "vert" de la variable "g", fueron previamente asociados a los checkbuttons e inicializados como "verdadero" o "opción activada"

Hay mucho mas que aprender de este ejemplo, te invito a estudiar como es que lo demás funciona.

Tuesday, May 6, 2014

Carrera de caballos (o etiquetas en el canvas)

He estado pensando en proveer pequeñas dosis de Tcl a través de ejemplos.
Es decir, crear ejemplos cortos que ilustren un concepto básico. Pero, porque no usar los excelentes ejemplos ya creados en el wiki de Tcl?
Ahora bien, que valor agregado puede tener el re-uso de ejemplos ya disponibles en otro sitio?
Creo que la respuesta a eso es:
- Mi explicación está en español
- Me enfocaré en algún concepto especifico que pueda servir al principiante
- Daré mi propia versión acerca de como es que funciona alguna sección del código existente y/o algún tip al respecto.

Veamos si esta idea puede servirle a alguien...

Tema: Etiquetas (tags) en el canvas
Ejemplo de referencia: "Horseracing in Tcl"
(solo se muestra aqui un proc)



* El proc horse "arma" (equino y jockey) para cada uno de los 10 caballos en la variable "horses"
* En amarillo, observe como se asocian varias lineas y óvalos a través de una etiqueta (tag), como un solo elemento, llamado:
horse0, horse1...horse9
* Subrayado en rojo, cada caballo, una vez creado, se va posicionando en coordenadas:
x (fija en 70)
y (cambiando) en incrementos de 30 + un "offset" de 14
* Subrayado en azul, es también interesante ver como se toman colores al azar, a partir de diferentes "sets" usando el procedimiento 'lpick'
* Y, para finalizar (por hoy), véase la creación de "cajas de captura" (entry) en el canvas, usando la siguiente linea de comando:

Listo para programar?
arrancan!


Monday, May 5, 2014

BLT 101

BLT es una extension para Tk, el cual agrega la capacidad de realizar varios tipos de gráficas, "geometry managers" -no sé como traducir esto ultimo, y otros comandos de utilidad:
http://incrtcl.sourceforge.net/blt/

Como les habia comentado en una publicación anterior, la versión de Tcl que tengo instalada es:
(ActiveState ActiveTcl 8.4.20.0) 1 %

No tengo instalado BLT en este momento:
% package require BLT
can't find package BLT

Pero tengo RBC, lo cual significa (Refactored BLT Components).
Veamos si funciona el ejemplo mínimo:

% package require rbc
0.1
% rbc::barchart .g -title "a chart example"
.g

% pack .g

Hasta ahorita, se ve así:



Crear una serie de datos:
% .g element create BT1 -xdata {1 2 3 4 5 6 7 8}\
-ydata {.76 .98 .88 .92 .96 .98 .91 .80}\
-label "Series 1" -showvalues y
BT1

Otra serie mas:
% .g element create BT2 -xdata {1 2 3 4 5 6 7 8}\
-ydata {.1 .2 .3 .4 .5 .6 .7 .8}\
-label "Series 2" -showvalues y -foreground red
BT2

Por alguna razón no veo la segunda serie de datos...
Checando bien la documentación, veo que debo configurar la gráfica de este modo:
% .g configure -barmode aligned

Ahora si:


Como en el caso del canvas, este ejemplo de BLT es el mínimo, te recomiendo la pagina del Tcl wiki:
El cual es un buen punto de partida para explorar las muchas otras prestaciones de este librería (o extensión)

Muy pronto, publicaré algunos otros ejemplos con BLT, ya que es una de mis extensiones favoritas y que me ha resultado muy útil.

Hasta la próxima!



Sunday, May 4, 2014

canvas para principiantes

Uno de los controles mas flexibles y potentes en Tcl (mas bien en Tk), es el canvas. La traducción de canvas en "lienzo" y si, el nombre ilustra fielmente lo que se puede hacer sobre el...casi cualquier cosa que te permita tu imaginación.

Que mejor que explicarlo a través de ejemplos, usando una sesión interactiva...

Primero, vamos a crear un canvas llamado .c, de esta manera:
% canvas .c -width 600 -height 600
.c

Para visualizarlo, hay que empacarlo:
% pack .c


Pongamos un par de lineas en el canvas:
% .c create line 100 0 100 500
1

% .c create line 200 0 200 500
2

A crear otras tres haciendo uso de un "for":
% for {set i 300} {$i < 600} {incr i 100} {
> .c create line $i 0 $i 500}

Ahora, completemos una cuadricula creando 5 lineas horizontales:
% for {set i 100} {$i < 600} {incr i 100} {
.c create line 0 $i 500 $i}

y que tal un circulo (a través del subcomando "oval"), en una de las celdas:
% .c create oval 100 100 200 200
15

Tambien un arco..
% .c create arc 200 200 300 300
16

un rectángulo muy cuadrado:
% .c create rectangle 310 310 390 390
17

y para terminar, agreguemos un texto:
% .c create text 410 410 -text "TclBits"
18

pero...que pasó?
esperaba verlo dentro de la cuadricula...
Ah! ya veo que el default de posición es centrado, de modo que esas coordenadas dejan una parte del texto invadiendo la celda vecina...

Veamos que pasa si cambio la posición "anclada" al este:

% .c create text 410 430 -text "TclBits" -anchor e
20

Ah! ya entendí, en realidad lo que necesitaba era "anclarla" al oeste (west):
% .c create text 410 450 -text "TclBits" -anchor w
21



Lo presentado es apenas la punta del iceberg de lo que se puede hacer con el canvas de Tk, hay algunos ejemplos en el wiki que abren una ventana a todo el potencial de este control.
por ejemplo: http://wiki.tcl.tk/4206

Mas del canvas...muy pronto.

Saturday, May 3, 2014

tablelist

tablelist es una libreria para presentar (y editar) datos en una tabla.
http://www.nemethi.de/
Es muy facil de usar.

Primero, hay que agregar la libreria a nuestro codigo, de esta manera:

package require tablelist

Preparemos la variable para el control (widget) de esta tabla:

set tbl .tbl

Ya podemos crear la tabla, en este caso:

  • 5 columnas (titulos de columna: A,B,C,D y E)
  • ancho de columna (0 = auto ajustable)
  • height = altura de la tabla en lineas
  • width = ancho de la tabla en caracteres

tablelist::tablelist $tbl \
 -columns {0 "A" 0 "B" 0 "C" 0 "D" 0 "E"}\
 -height 15\
 -width 100
Finalmente, a "empacar" el control en la ventana principal
pack $tbl

Para insertar datos en la tabla, se usa el comando...insert con los datos a insertar en una lista.

$tbl insert end [list a b c d e]
 
Vea como configuramos la celda del ultimo renglon, primer columna con letras blancas en fondo rojo:Notese que en ese momento, el ultimo renglon es el que acabamos de insertar y que la numeracion de celdas inicia con cero.

$tbl cellconfigure end,0 -foreground white -background red

Insertamos mas datos, y configuramos la celda del ultimo renglon, segunda columna con letras blancas en fondo azul:


$tbl insert end [list a b c d e]
$tbl cellconfigure end,1 -foreground white -background blue
Y para terminar, letras negras en fondo verde, para la celda en ultimo renglon, tercer columna:

$tbl insert end [list a b c d e]
$tbl cellconfigure end,2 -foreground black -background green
Este es el resultado:


Friday, May 2, 2014

Un ejemplo de "parseo" con htmlparse

Para ejemplificar como "Lemon Tree Branch" puede ser usado como una herramienta para el parseo de paginas web, que mejor que tomar una página donde podrás encontrar excelentes scripts de los cuales puedes aprender lo mejor de las técnicas de programación usando Tcl/Tk. La página en cuestión es la correspondiente a Richard Suchenwirth en el wiki.
Primero, copié la dirección URL en la caja de texto destinada para ello.
Tuve que también "descomentar' las lineas siguientes en Lemon Tree Branch:

htmlparse::removeVisualFluff t
htmlparse::removeFormDefs t


Como se puede observar, la "ruta" a la lista de ejemplos de Richard es:
1-15-0, desde la raíz, hasta el primer tag


Ahora si, este es el programa ejemplo donde se pueden apreciar los beneficios de poder usar la funcionalidad de la estructura "tree", tal como por ejemplo:
t next $bulletIx
con lo cual se puede hacer iteraciones en elementos del mismo "nivel"



Nótese que:

  • Solo estoy "tomando" un solo link por "bullet", de modo que, por ejemplo, no estoy capturando el link para "A pocket Wiki", el cual es el segundo link en uno de los "bullets"



  • Hay un mensaje de error: (node "" does not exist in tree "t") cuando no hay link en el "bullet", como en "simplicite"






Obtener todos los links que haya por "bullet" puede ser un buen ejercicio para el lector.

console show
  
package require struct
package require htmlparse
package require http
  
proc parse {} {
  
::struct::tree t
  
set url "http://wiki.tcl.tk/1683"
set http  [::http::geturl $url]
set html  [::http::data $http]
  
htmlparse::2tree $html t
htmlparse::removeVisualFluff t
htmlparse::removeFormDefs t
  
set base [walk {1 15 0}]
    puts "data: [t get $base data]"
    puts "type(tag): [t get $base type]\n"
  
    set bulletIx   [walkf $base {0}]
  
while {$bulletIx != {}} {
      set link  [t get [walkf $bulletIx {0}]  data]
      #set title [t get [walkf $bulletIx {0 0}]  data]
      catch {t get [walkf $bulletIx {0 0}]  data} title
      puts "$link: $title"
      update
      set bulletIx [t next $bulletIx]
}
  
   t destroy
   return
}
  
proc walkf {n p} {
    foreach idx $p {
        if {$n == ""} {break}
        set n [lindex [t children $n] $idx]
    }
    return $n
}
  
proc walk {p} {
    return [walkf root $p]
}
  
parse

Thursday, May 1, 2014

HTML en un arbol

El parseo de paginas web con las librerias htmlparse y html2tree, usa las "rutas" a los puntos de interés dentro de la estructura jerárquica del archivo html.
En el wiki de Tcl, descubrí un código ejemplo llamado "LemonTree" el cual generaliza el llenado de un control BWidget tipo arbol con elementos de una jerarquía.
Ejemplos de estructuras de datos jerárquicos son: el sistema de archivos, los controles en una interface gráfica hecha con Tk, los comandos y las variables en los "namespaces",etc.

Por otro lado, LemonTree explica claramente como agregar otras estructuras jerárquicas a este control, lo cual viene perfecto para el caso de los tags dentro de un archivo html.
Una vez que se puede explorar el contenido del archivo html en un control de este tipo, se está en la posibilidad de utilizar este script a manera de herramienta para facilitar la determinacion de la ruta a los elementos de interés.
En esta ocasión, les presento el código al cual le llame' "LemonTree Branch" en la publicación original, para hacer referencia al script en el que esta basado.
Mañana, veremos un ejemplo de parseo de una pagina web, para lo cual, utilicé este script para encontrar la mencionada "ruta" el punto de inicio de los elementos que me interesa extraer.

Como se usa:
1) Si se tiene el archivo html almacenado de manera local.
a) Navegar a la ubicación del archivo haciendo click en el botón "Browse..."
b) Hacer click en el botón "html > tree"
c) Empezar la exploración del árbol haciendo click en los nodos

2) Si el archivo es una pagina web estándar.
a) Copié la dirección (URL) desde el navegador web a la caja de texto
b) Hacer click en el botón "html > tree"
c) Empezar la exploración del árbol haciendo click en los nodos

En la consola, se puede observar la secuencia de ruta, desde el punto seleccionado hasta la raíz. Vale la pena aclarar, que dicha secuencia, normalmente se requiere en el sentido contrario, o sea, desde la raíz, hasta el punto deseado.



package require struct
package require csv
package require report
package require htmlparse
package require textutil
package require http
package require BWidget
namespace eval LemonTree {variable uniqueID 0}

#http://www.cs.grinnell.edu/~walker/fluency-book/labs/sample-table.html

if 0 {The Tree widget allows a -data item for each node, which I use for a dict-like
list that contains the node's type and "real name" (as opposed to the "display name"
- for instance, a dir node would display only its [file tail], but the real name is
the full path). This routine adds a node to the LemonTree: }

 proc LemonTree::add {w parent type name {text ""}} {
    variable uniqueID; variable icon
    if {$parent != "root"} {
      set val1 [::t get $name data]
      set val2 [::t get $name type]
      set val3 [::t index $name]
      if {$text eq ""} {set text "$val3: <$val2> [string range $val1 0 30]"}
      #if {$text eq ""} {set text "$val3,$val2,$val1"}
    }
    set id n[incr uniqueID]
    set data [list type $type name $name]
    #tk_messageBox -message "$type,$name"
    set fill [expr {[string match (* $text]? "blue": "black"}]
    set drawcross [expr {[info proc ::LemonTree::kids($type)] eq ""?
         "never": "allways"}]
    $w insert end $parent $id -text $text -data $data -drawcross $drawcross -fill $fill
    if [info exists icon($type)] {
             $w itemconfigure $id -image $icon($type)
    }
 }
if 0 {For speed, a Tree isn't drawn fully expanded at the beginning.
Instead, nodes are opened on demand, when the user clicks on the [+] icon.
I use the -drawcross "allways" mode (shudder - should be fixed to "always",
but then older code might break) to indicate that the node hasn't been opened before
- after the first opening, the mode is set to "auto", meaning to draw a cross only if the node has children. }

proc LemonTree::open {w node} {
    if {[$w itemcget $node -drawcross] eq "allways"} {
        set data [$w itemcget $node -data]
        set type [dict'get $data type]
        foreach {ktype kids} [kids($type) $w $node] {
            foreach kid $kids {add $w $node $ktype $kid}
        }
        $w itemconfigure $node -drawcross auto
    }
 }

if 0 {So far for the generic LemonTree - the rest is already customization for specific item types.
The kids($type) call above looks like an array element 
- in fact it's a way of dispatching the generic operation of providing the list of children
of an entity of given type, which of course depends on the type. For instance, the children
of a directory are its subdirectories, and then its files (with special-casing for Windows,
so that drive letters are the children of "/"): }

 proc LemonTree::kids(html) {w node} {
    set name [dict'get [$w itemcget $node -data] name]
    list html [::t children $name]
 }

if 0 {A Tree looks prettier if nodes have icons, so I'm using some of those that BWidget comes with:}
set path $BWIDGET::LIBRARY/images

foreach {type name} {dir folder file file array copy html folder} {
   set LemonTree::icon($type) [image create photo -file $path/$name.gif]
}

if 0 {This thing is more useful if you can get more information about an item by clicking on it
- for a file, its size and date; for a variable, its value; for a proc, its full specification, etc.
As a small first shot, I selected a "balloon" for that purpose. }

proc LemonTree::Info {w node} {
    set type [dict'get [$w itemcget $node -data] type]
    if {[info proc ::LemonTree::info($type)] ne ""} {
        balloon $w [info($type) $w $node]
    }
 }
 
#-- type-specific info providers:

 proc LemonTree::info(html) {w node} {
    #puts $node
    set name [dict'get [$w itemcget $node -data] name]
    if {$name != "root"} {
      set val1 [::t get $name data]
      set val2 [::t get $name type]
      set val3 [::t index $name]
      puts $node
      puts "\t[t index $name]"
      foreach nodo [t ancestors $name] {
       if {$nodo != "root"} {
         puts "\t[t index $nodo]"
       }
      }
    } else {
     set val1 "root"
    }
    return "$val1"
 }
 
#-- A simple ballon, modified from Bag of Tk algorithms:  
proc balloon {w text} {
    set top .balloon
    catch {destroy $top}
    toplevel $top -bd 1
    pack [message $top.txt -aspect 10000 -bg lightyellow \
        -borderwidth 0 -text $text -font {Helvetica 9}]
    wm overrideredirect $top 1
    wm geometry $top +[winfo pointerx $w]+[winfo pointery $w]
    bind  $top <1> [list destroy $top]
    raise $top
 }

if 0 {From Tcl 8.5, one would use a real dict, but it's easy to make a replacement
that works roughly the same in 8.4 (it returns "" for non- existing keys instead of throwing an error),
and might be slower, but I won't notice on dicts with two elements ;-}

proc dict'get {dict key} {
    foreach {k value} $dict {if {$k eq $key} {return $value}}
 }
#-- reconstruct a proc's definition as a string:
proc procinfo name {
    set args ""
    foreach arg [info args $name] {
        if [info default $name $arg def] {lappend arg $def}
        lappend args $arg
    }
    return "proc $name {$args} {[info body $name]}"
 }
 
#
#
#
proc main {} {
  set url [.txt get]
  catch {t destroy}
  .t delete [.t nodes root]

  if {$url == ""} {
  tk_messageBox -message "specify html location"
  return
  }
  ::struct::tree t
  if {[string range $url 0 3] == "http"} {
    set http  [::http::geturl $url]
    set html  [::http::data $http]
  } else {
    set html [read [set fh [open $url]]]
    close $fh
  }
  
  #puts $url
  htmlparse::2tree $html t
  #htmlparse::removeVisualFluff t
  #htmlparse::removeFormDefs t
  LemonTree::add .t root html    root  "(html)"
  
return
}
 
# -------------------------------------------
label .lbl -text "URL or path:"
entry .txt -width 60
button .btnBrowser -text Browse... -command {.txt insert end [tk_getOpenFile]}
button .btnGet -text "html > tree" -command main
button .btnSalir -text Exit -command {
catch {t destroy}
exit
}
grid .lbl .txt .btnBrowser
grid .btnGet -row 1 -column 1
grid .btnSalir -row 1 -column 2

#-- Now to demonstrate and test the whole thing: 
Tree .t -background white -opencmd {LemonTree::open .t} \
-width 60 -height 30 -yscrollcommand {.y set}
 .t bindText  <1> {LemonTree::Info .t}
 .t bindImage <1> {LemonTree::Info .t}
 
scrollbar .y -command {.t yview}

grid .t -row 2 -column 0 -columnspan 3 
grid .y -row 2 -column 3 -sticky ns
.txt insert end "http://www.cs.grinnell.edu/~walker/fluency-book/labs/sample-table.html"
#-- Little development helpers:
bind . <Escape> {exec wish $argv0 &; exit}
bind . <F1> {console show}