tpad

[ Intro | Download | Docs | How to install/upgrade | Bugs | Notes for qvwm users | Contributing | Mirrors ]

help

Using tpad in your own programs

Introduction and legalese

Starting from version 1.3 tpad has been packaged as a Tcl library to make it easier to reuse it into your own programs. In most cases it will suffice to call tpad as a subprocess using exec(n) and its command line interface. But if you need more control over a tpad instance and you don't want to make use of the potentially insecure send(n) mechanism you should invoke and control tpad as a library of commands.

You can use and modify tpad any way you see fit, but please don't violate the licence! Remember that tpad is distributed under the GNU General Public Licence version 2 or later and so must be any derivative work. If you are writing proprietary software or using any other licence different from GPL you can't use tpad with your own software without prior asking the author for written permission - this for commercial software means you will have to pay some money to me :-)

The tpad simple API

tpad is not object oriented, mainly because I didn't want to add [incr Tcl] as another dependency.

The first thing to do to use the tpad package is to require it:

package require tpad

This will try to require the highest version number available. It returns the version number or an error if tpad is not installed. See the package(n) manual page for details about requiring exact version numbers.

tpad uses the Tcl auto-loading facility. This means that requiring it won't cause the library (tpad.tcl) to be loaded immediately. Instead the loading will be delayed until the first use of one of tpad exported commands. In other words, only requiring tpad won't cause any overhead at all. The library will only be sourced when it is effectively used. This reduces start-up time for interactive programs.

Optionally from now you can import all the public tpad commands using:

namespace import ::tpad::*

Using namespace(n) import will allow you to access all the tpad commands without using the ::tpad:: prefix, but occasionally can cause errors of name collisions. This happens every time you import another package command which has the same name as a tpad exported command. In the following we will continue to use the ::tpad:: prefix before every tpad command, assuming you have not imported any of them. You can also import tpad commands individually, to reduce the risk of name collisions. For example, to only import the tpad and display commands use:

namespace import ::tpad::tpad ::tpad::display

For an updated list of exported commands please see the library file (tpad.tcl) and look for "namespace export" commands.

Next, you have to create a tpad instance. This must be done before calling every other commands (except ::tpad::cmdHelp and ::tpad::whatIs because they don't require a pathname as argument). A tpad istance displays itself into a toplevel widget or the main application window (pathname .). Use the toplevel(n) command to create and configure a new toplevel for using with tpad. Then use the ::tpad::tpad command to initialize a new tpad instance. Its first argument is a pathname to the window to use. The second argument should be something as "tpad" for the editor or "tview" if you want to use tpad as a viewer (pager). As described above, this command will auto-load the tpad library if it hasn't been sourced yet. Examples:

::tpad::tpad . tpad
::tpad::tpad .txt tview
toplevel .txt

The third argument is optional and must be a list of options with the same syntax as used on the command line. For further details on this please see Command line usage or refer to the tpad(1) manpage. Example:

::tpad::tpad . tpad +10 file1 /path/file2

If you want to pass on the command line options you must use eval(n) otherwise $argv will be transmitted as a single argument to the tpad proc and that won't work correctly if argv has more than a word or is empty:

eval ::tpad::tpad . $argv0 $argv

Here we are using the program name argv0 to distinguish between the editor and the viewer.

In order to display tpad you now call the display proc, passing along the pathname:

::tpad::display .

This is where all the menus, key bindings, callback functions are defined and widgets are packed. If you plan to reuse tpad code to build an integrated editor for another program (e.g. a mail reader, a debugger, an IDE, and so on) you may want to provide your own modified version of the display proc and possibly other callbacks (or redefine some of them). Remember, as long as you comply with the GPL licence, you are free to reuse the tpad code as is or heavily modify it and make a new derived package from it.

The pathname (abbreviated as pn in argument lists) is used as the first parameter in almost every other exported command. Think of it as the current object or the "this" pointer in object oriented programming. You can have multiple instances of tpad as long as they use different pathnames and you will use a unique pathname to distinguish between them. For example try this:

toplevel .tpad1
toplevel .tpad2
::tpad::tpad .tpad1 tpad
::tpad::tpad .tpad2 tpad
::tpad::display .tpad1
::tpad::display .tpad2

These are some examples of other calls. The first one returns the total number of lines in the text typed so far, for the instance . (this will be at least 1, because there is always at least an empty line in the text):

::tpad::lines .

This will have the same effect as the user selecting the File/Save options for the tpad instance called .tpad2:

::tpad::save .tpad2

If you don't want to use temporary files for exchanging the text to be edited between tpad and your application, tpad supports editing directly a variable. You decide if you want to make tpad window modal or not (see grab(n)). Use the variable name as an additional argument to the display proc. You also have to use trace(n) to register a callback function to be called when the variable is updated (this happens when the user exits from tpad and confirms to save the editing), otherwise you won't have a simple and efficient way to know that the variable has changed. This is an example of how to make use of this feature:

set txt {This is
the txt to edit.}

trace variable txt w txtChanged

proc txtChanged {variableName elementName operation} {
  # remember that this proc executes at the same
  # stack level as the access to the variable txt

  puts "txt variable modified.\nThe new value is:\n$::txt"
}

toplevel .ed
grab .ed ;# use a modal edit window (optional)

::tpad::tpad .ed tpad
set ::tpad::titlefmt {my thoughts}
::tpad::display .ed txt

# ...

Note about destroying a tpad toplevel: when a new toplevel widget other than . is used for tpad (e.g. .tpad), you have to remember to explicity call the tpad quit procedure within the parent event handler. If you don't do it, when the parent window is closed before the tpad window is, tpad will also be destroyed without providing the user with a last change to save his changes (if any). Here is how to test if tpad is still opened and provide a clean quit from it, if needed:

toplevel .tpad
wm protocol . WM_DELETE_WINDOW {
  # this is the parent closing handler
  # ...

  if {[namespace exists ::tpad::.tpad]} {
    ::tpad::quit .tpad ;# clean quit from tpad
  }

  # ...
  # tipically you will have a "destroy ." as the last command
}

eval ::tpad::tpad .tpad
::tpad::display .tpad

[ Return to Contents ]

Valid HTML 4.01! Petition for a Software Patent Free Europe Eliminate DRM noooxml

Last modified: Sunday, 18-Apr-2010 09:36:29 UTC