License
=======

This code is in the public domain. Use, modify, redistribute with or
without modification, or license it as you see fit.

Warning: tk_octave is mostly unsupported.  Probably a better solution is to 
use extra/soctcl from octave-forge.  

If you decide to pursue tk_octave, please bear in mind that
the code is not safe as it is currently written.   Since octave's
reference counting classes do not use semaphores, there
is a small window in which a task switch could delete
an array in octave while tcl wanted to access it.


Manifest
========

Files in this package are:

readme.txt		This file

sample.dat		Some sample Octave data, a 100x100 matrix

tk_interp.cc		C++ source for a dynamically loaded Octave module
			Contains routines for using BLT/VTK with Octave

tk_matrix.tcl		Example Tcl/Tk GUI which uses BLT/VTK with Octave

tk_matrix		Executable script that runs Octave and loads the
			GUI from tk_matrix.tcl

Makefile		The Makefile for tk_interp.cc

rainbow.m		A colormap function

tk_*.m			Various user interaction dialogs


Compiling Octave with tk_interp.cc
==================================

In order to use tk_interp, you may need to relink the Octave binary with
pthreads.

1) Untar/gz the octave source to /someplace/octave

2) Change directory to /someplace/octave and run ./configure

4) Edit /someplace/octave/Makeconf, changing

	LIBS = ...

   to

	LIBS = ... -lpthread

   or maybe

        LIBS = ... -lpthreads

5) Change directory to /someplace/octave and run 'make' and optionally run
   'make install' afterwards.  After installation (which by default is in
   /usr/local/bin), rename octave to octave-pthreads and mkoctfile to
   mkoctfile-pthreads


Creating tk_interp.oct
======================

After relinking a custom version of Octave with pthreads, you'll need to 
create tk_interp.oct.  Modify Makefile in the tk_octave directory to
reference the appropriate mkoctfile for your custom version of Octave,
and comment out TCL_OPTS=, BLT_OPTS= or VTK_OPTS= as appropriate.
Type make and it should create tk_interp.oct for you.

Note that to use BLT and VTK, you will need to link with code distributed
under four different licenses:

   1) Octave uses a GPL license.
   2) Tcl/Tk uses a BSD-style license without advertising clause,
      which is said to be GPL compatible.
   3) BLT uses a BSD-style license with advertising clause, which
      is said to be GPL incompatible.
   4) VTK uses a BSD-style license without advertising clause, but
      with a restriction against redistributing with modifications.

The FSF considers linking as equivalent to modification.  Since
Octave is GPL, this would mean that all parts of the program have 
to be compatible since they won't work unless they are linked.
Since this interpretation of the GPL has not yet been tested in
any court, use your own judgement.

Some simple tests
=================

Is it alive?

	$ octave-pthreads
	tk_interp
	tk_cmd('toplevel .msg')
	tk_cmd('button .msg.hello -text "Hello, world!" -command {destroy .msg}')
	tk_cmd('pack .msg.hello')

Can you get data from it?
        tk_cmd('toplevel .data');
	tk_cmd(sprintf('set value %f', pi));
	tk_cmd('entry .data.entry -textvariable value');
        tk_cmd('pack .data.entry');
	tk_cmd('bind .data.entry <Return> {destroy .data}');
	tk_cmd('tkwait window .data');
	mypi = eval([tk_cmd('set value'), ";"])

Try one of the built-in dialogs

	tk_message("Hello, world!");

Running the BLT/VTK example
===========================

In the tk_octave directory you should now be able to run the main example.
This requires BLT, and can use TkTable and VTK if you have them. The 
tk_matrix script needs to know the location of your custom version of 
octave.  If it is not in /usr/local/bin/octave-pthreads, change the top 
line of the script as appropriate, then type:

	$ ./tk_matrix

If you get the message that oct_mtov is not a proper command, then you 
haven't specified OPTS = $(BLT_OPTS) in the Makefile.

The example lets you view a 2D matrix of octave data as an image.  Click
with the middle button to look at the X-Y cross sections at that point.
Click with the left button, move, and click with the left button to zoom
into a region of the matrix.  Click with the right button to return to the
full image.  Click the "Table" button to view the data in a spreadsheet.

You can type octave commands directly into the command window.  E.g.,
    logsample = log(1+sample);

You can view a different matrix by typing its name into the matrix
name window.  Assuming you have defined logsample as above, then
enter "logsample" into the window and press return.

How it works
============

tk_interp.cc defines the following new commands in octave:

  window_name = tk_interp() 
     starts the tcl interpreter
  result = tk_cmd()
     sends a tcl command to the tcl interpreter
  tk_loop()
     waits on the tcl interpreter, processing callbacks as needed
  tk_end()
     ends the tcl interpreter

tk_interp.cc defines the following new commands in tcl:

  oct_cmd command
    sends a callback to the octave interpreter.  All arguments are
    glued together as one long command string.
  oct_matrix name [exists|rows|cols|columns|min|max]
    grabs info about a matrix from octave
  oct_matrix name [elem|element] i j
    grabs name(i,j) from octave
  oct_string exist
    grabs info about a string from octave
  oct_string name
    grabs name as a string from octave
  oct_mtov name vector x y sizex sizey
    grabs name(x:x+sizex,y:y+sizey) from octave and places
    it into a BLT vector.
  oct_mtovtk name VTKname
    grabs a matrix from octave and places it into a VTK data structure
  oct_quit 
    ends the Octave interpreter

  Note that if name starts with global::, it searches the global symbol table,
  if name starts with top::, it searchs the top level symbol table.  If name
  starts with current::, it searches the current symbol table.  The default
  is to search the top level symbol table.

  WARNING!!! There are concurrency issues to sort out which can be 
  especially severe with current::, so use with caution.


tk_interp also defines a new image format:

  image create photo tclimage
    defines a new variable tclimage which will contain a photo
  tclimage configure -data "name"
    like imagesc, scales the image according to the current colormap
    This requires the following octave declaration before it will work:
       global __current_color_map__ = gray(64);
    Both name and __current_color_map__ are variables in the top level
    symbol table.
  tclimage configure -data "name -colormap map"
    like imagesc, scales the image according to the colormap map
    Both name and map are octave variables in the top level symbol table
  tclimage configure -data "name -indexed"
    like image, doesn't scale the image, but assumes that it's values
    are are 1-origin indices into the colormap

Projects
========

Modify tk_matrix.tcl so that you can enter either "z" or "x y z",
and update the x and y axis limits appropriately.  Also give the
programmer control over x, y and z axis labels and matrix title.

Implement variable notification so that when the value changes in
octave, the tcl matrix gets redrawn.

Define a widget type in octave along with packing commands so
that the user interface can be implemented entirely in Octave.

Sort out concurrency issues.  Currently the tcl thread is looking at the
octave variables while octave is running in a separate thread.  To see
how much of a problem this is in practice, enter "sample" as the tk_matrix
name (and press return), then type the following octave command:

    for i=1:rows(sample), for j=1:columns(sample), sample(i,j)=log(1+sample(i,j)); end; end;

While that command is executing, click on the matrix name entry box and press
return.  You will see the matrix slowly change from linear to log scale.
On my machine, this doesn't crash.  These are a couple of real race
conditions underlying which could lead to a seg_fault, but the window is
very small (not much wider than the amount of time it takes to copy the
octave_value reference and update its reference count.  In practice, the
octave main loop is going to be sitting in tk_cmd or tk_loop during almost
all GUI interaction, so the issue will never come up, but you will have to
think carefully about what you put in your tk_cmd and oct_cmd commands to
be sure.  See SAFE_VAR in tk_interp.cc.
