Creating new widgets

\c{ By virtue of the class structure and inheritance mechanism of C++ new widgets may easily be created. An example is provided by the filechooser widget provided by hush. The filechooser widget merely groups an entry, button and listbox in an appropriate way and allows the user to install a handler to retrieve the selected filename. } \sli{
  interface filechooser : widget { 
\fbox{filechooser}
filechooser();
to create an exemplar (see section creation)
filechooser(char* p, char * options = ""); filechooser(widget* w, char* p, char * options = ""); char* get(); };
} \c{ The filechooser has been implemented by a mixture of Tcl and C++ code. In order to make the filechooser also available as a widget to be used in Tcl scripts some additional work is required. Recall that, when creating a widget in Tcl/Tk, the path name of the widget defines a command that may be used to perform operations (such as configure) on the widget, in an object-like manner. } \c{

Dispatching

For a widget (not already defined by Tk) to act as a command it must be able to figure as a handler object, for which the function dispatch is invoked whenever it is treated as a command. The dispatch function for the filechooser class is shown below. } \sli{
  private:
  filechooser* f;
  
  int dispatch( kit* tk , int argc, char** argv ) {
  	f = this;
  	if ( !strcmp("filechooser",*argv) )
  		return create(tk, --argc, ++argv);
  	argv++; 
  	while ( argc-- > 1 ) {
  	if ( !strcmp("configure",*argv) ) 
  		return options(tk, argc,++argv);
  	else if ( !strcmp("get",*argv) ) { f->get(); return OK; }
  	else cout << " no such option " << endl;
  	argv++;
  	}
  	return OK;
  }
  
} \c{ In other words, the class filechooser combines three roles, namely in the first place that of a widget class defining the functionality of a widget, secondly it implements the command filechooser that is used to create a widget, and thirdly it embodies the command associated with (the path name of) the widget. For the dispatch function there is an ambiguity with respect to what object is referenced. When creating a new widget, the object referenced must still be created. However, if the widget already exists it will reference itself when treated as a command. To resolve this ambiguity, an additional pointer f is introduced that will reference the object itself unless the reference is changed by invoking create. } \sli{
  int create(kit* tk , int argc, char** argv) { 
  	f = new filechooser(*argv);
  	tk->action(*argv,f);
  	tk->result(*argv);
  	return options(tk,--argc,++argv);
  	}
  
} \c{ The function create creates a new (filechooser) widget and associates the path name of the widget with an action taking the newly created widget as the handler object. Then (in conformance with Tk conventions) it sets the result of the action to the path name of the newly created widget. } \c{

Example

The filechooser widget command may now be used in a same way as the standard Tk widget commands. } \sli{
  filechooser .ff -command {puts stdout [.ff get]}
  
  pack append . .ff {top}
  go-back
  
} \c{ In order to make the filechooser command available as a Tcl command, an instance of filechooser must be created to be associated with the command of that name as a handler object. } \sli{
  void install(kit* tk, int, char** ) {
  handler* h = new filechooser;
  tk->action("filechooser",h);
  }
  
  int main (int  argc, char  **argv) {
      session* s = new session(argc,argv,"root");
      s->install(install);
      return s->run();
  }
  
} \c{ In the function main above, no program function is given to run. This restricts the executable to be useful for interpreting scripts only. When, after interpreting a script, also a program function must be executed, the script must contain the command go-back as its last command. }