The TOAD C++ GUI Library

TOAD is...

Learn more:

Features

The TOAD C++ GUI Library provides some standard features found in other GUI libraries like

The following features are unique:

Other planned features are, for example, a C++ scripting language to create a complete User Interface Management System (UIMS) for Rapid Prototyping.

Download

Stable Release

Stable means that the API will not change for all 0.64.x releases.

toad-0.64.1.tar.bz2 [gpg sig] (uploaded Tue, 03 July 2007 22:30:40)

Requires GNU C++ 3.0 or higher, the X Window System, libpng and fontconfig 2.2.0 or higher.

Manual

toad-manual-2004-01-31.tar.gz

Subversion

Development releases are available via Subversion:

svn checkout https://svn.mark13.org/toad/trunk/toad toad
cd toad
svn checkout https://svn.mark13.org/toad/trunk/examples examples

(Browse online)

There is also an experimental port to Mac OS X:

svn checkout https://svn.mark13.org/cocoa/trunk cocoa

(Browse online)

Other stuff

Applications, old releases and snapshots, etc.

Hello World

This program subclasses the class TMyWindow from TOAD's window class TWindow and displays it.

The command

g++ `toad-config --cxxflags --libs` hello.cc

will compile the program.

// include declarations of TOAD basic classes
#include <toad.hh>
 
// use the TOAD namespace
using namespace toad;
 
// define a new window class, based on TWindow
class TMyWindow:
  public TWindow
{
  public:
    // typical constructor for windows
    TMyWindow(TWindow *parent, const string &title)
      :TWindow(parent, title) {}
    
    // define a new method to paint the windows content
    void paint() {
      // create a pen for this window and use it to...
      TPen pen(this);
      // ...draw a text at position (50, 50)
      pen.drawString(50, 50, "Hello World!!!");
    }
};
 
// initialize TOAD, create window and enter the message loop
int
main(int argc, char **argv, char **envv)
{
  // initialize TOAD library
  toad::initialize(argc, argv, envv);
 
  // create window
  TMyWindow *window = new TMyWindow(0, "Hello World");
 
  // show window and handle user input until window is closed
  toad::mainLoop();
  
  // the window has been closed so we dispose of the object
  delete window;
 
  // clean up TOAD
  toad::terminate();
 
  return 0;
}

Dialog Editor

The dialog editor is integrated into the library and can be used at runtime.

This was done because most ideas on how to fine tune the layout of a program come when one actually uses the program.

Step 1: Write the Code

#include <toad/toad.hh>
#include <toad/dialog.hh>
#include <toad/textfield.hh>
#include <toad/pushbutton.hh>
 
class TMyWindow:
  public TDialog
{
  public:
    TMyWindow(TWindow *parent, const string &title);
 
    void printData();
 
    // the data we're going to edit
    TTextModel name, surname;
    TUnsignedModel age;
};
  
int
main(int argc, char **argv, char **envv)
{
  toad::initialize(argc, argv, envv);
  {
    // tell TOAD where to store/read the resource files
    TOADBase::setResourcePrefix("file://resource/");   
    TMyWindow(NULL, "MyWindow");
    // start the application
    toad::mainLoop();
  }
  toad::terminate();
  return 0;
}
 
TMyWindow::TMyWindow(TWindow *parent, const string &title):
  TDialog(parent, title)
{
  // create the widgets
  TTextField *tf;
  tf = new TTextField(this, "name", &name);
  tf = new TTextField(this, "surname", &surname);
  tf = new TTextField(this, "age", &age);
 
  TPushButton *pb;
  pb = new TPushButton(this, "print");
  CONNECT(pb->;sigActivate, this, printData);
  pb = new TPushButton(this, "quit");
  CONNECT(pb->sigActivate, this, closeRequest);
  
  // set a resource name for the layout
  doLayout("MyWindow");
}  
 
void
TMyWindow::printData()
{
  // print the data                                
  cout << "Name   : " << name << endl                    
       << "Surname: " << surname << endl                    
       << "Age    : " << age << endl;                    
}

Step 2: Execute your program

make
./program --layout-editor

When no earlier layout exists all the widgets are placed in the upper left corner of the window.

Step 3: Layout your widgets

Enable the layout editor and use the mouse to move and resize the widgets. You can even add additional graphical elements.

The dialog editor used here is names "TDialogLayout", which is the default for dialog windows. But one can easily use other layout algorithms, for example TSpringLayout.

Step 4: Fin

Once the layout is finished you can save the layout.

Callbacks

GUI applications are event driven, eg. the user pushes a button and an email is sent. The common way to do this is to create a TPushButton object and to instruct it to call you back when is was pushed:

class TMailApplication:
  public TWindow
{
  public:
    TMailApplication() {
      ...
      // create a pushbutton and...
      TPushButton *btn = new TPushButton(this, "Send emailpush me");                         
      // ... and tell it to call 'this->sendMail()' when it is pushed
      CONNECT(btn->sigClicked, this, sendMail);         
      ...
    }
 
    void sendMail() {     
      cout << "calling 'sendmail'" << endl;                                  
      ...
    }
};

The following happens here:

  • TPushButton contains an object named sigClicked of type TSignal. Each time TPushButton thinks that it was pushed, it calls sigClicked.trigger() which in turn calls all functions which were connected to it.
    In the example above the method sendMail() would be called.

  • CONNECT is a C pre-processor macro which utilises the GNU C Compilers 'typeof' operator to make the syntax a little bit more neat. When you don't want to rely on the existence of the 'typeof' operator, you may also write:
    connect(btn->sigClicked, this, &TMailApplication::sendMail);

Below are some more examples to get the feel of it.

A feature which do I consider extremly cool is the TCLOSURE macro below. It mimics SmallTalk closures and allows you to write the code to be called back at the same place where you connect it to TSignal.

#include <toad/connect.hh>
 
struct TMySource
{
  TSignal sigAction;
    int value;
    int getValue() { return value; }
};
      
struct TMyDestination
{
   void doIt(int n) { cout << "doIt: " << n << endl; }
};
        
int
main()
{
  TMySource *source = new TMySource();
  source->value = 42;
  TMyDestination *destination = new TMyDestination();
 
  // ANSI C+ compatible call interface
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  connect(
    source->sigAction,                   // when triggered
    destination, &TMyDestination::doIt); // call method
 
  connect_value_of(
    source->sigAction,                   // when triggered
    destination, &TMyDestination::doIt,  // call method
    source, &TMySource::getValue);       // with the return value of method
    
  connect_value_of(
    source->sigAction,                   // when triggered
    destination, &TMyDestination::doIt,  // call method
    &source->value);                     // with the return value of variable
 
  connect_value(
    source->sigAction,                   // when triggered
    destination, &TMyDestination::doIt,  // call method
    source);                             // with the return value of 'getValue()'
 
  // GNU C++ compatible call interface
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  CONNECT(
    source->sigAction,                   // when triggered
    destination, doIt);                  // call method
  
  CONNECT_VALUE_OF(
    source->sigAction,                   // when triggered
    destination, doIt,                   // call method
    source, getValue());                 // with the return value of method
  
  CONNECT_VALUE(
    source->sigAction,                   // when triggered
    destination, doIt,                   // call method
    source);                             // with the return value of 'getValue()'
  
  TCLOSURE2(                             // closure with two variables
    source->sigAction,                   // the signal
    dst, destination,                    // dst := destination
    src, source,                         // src := source
    dst->doIt(src->getValue()*10);       // and execute this code
  )
  
  // triggering a signal
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  source->sigAction();
  
  // disconnecting a signal
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  disconnect(source->sigAction);         // remove all links
}