Figure 1   A Simple Form Class


 #include "wrappers.h"
 #include "form.h"
 //----------------------------------------------------------------------
 class Employee: public Form::Element
 {
     Text name;
 
 private: // Form-related functions
     virtual Form::Proxy *give_me_proxy_for( const String &form_name,
                                             const String &attribute_id );
     virtual void        release_proxy     (Form::Proxy *p);
 
 
 public:
     Employee(const String &in_name): name(in_name){}
     void print(void) const{ ok_box( name ); }
 };
 //----------------------------------------------------------------------
 Form::Proxy *Employee::give_me_proxy_for( const String &form_name,
                                           const String &attribute_id )
 {
     // Set things up so input flows directly from the Form into the
     // Employee's Name field.
     //
     // Since "this" is passed as a second argument to the Proxy
     // constructor, the Employee will be notified (with a release_proxy
     // message) when the Form shuts down.
 
     Form::Proxy *p = new Form::Proxy( &name, this );
     assert( p );
     return p;
 }
 //----------------------------------------------------------------------
 void Employee::release_proxy(Form::Proxy *p)
 {
     // Sent from the form when it shuts down instead of deleting the
     // proxy (because we passed our address to the Proxy's constructor).
 
     ok_box("Form has shut down\n");
     delete p;                       // Form does not delete the proxy if
 }                                   // we're notified. Proxy's destructor
                                     // never deletes the associated
                                     // User_interface object.
 //----------------------------------------------------------------------
 Form *make_form(void)
 {
     // I get an internal compiler error if I try to just initialize
     // form, below, with the following new invocation. Putting the
     // new in a function call and initializing form with the
     // function's return value works fine, though.
 
     Form *form = new Form( "Test Form",
         new Form::Field( new Text("Name:"),        Rect(0, 0, 50, 20)),
         new Form::Field("Employee", "Name",        Rect(50,0, 200,20)),
         new Form::Field( new Form::Close_button(), Rect(80,25,120,45)),
         NULL
         );
 
     form->debug_print();
     return form;
 }
 //----------------------------------------------------------------------
 Form *form = make_form();
 Employee homer("Homer");
 //----------------------------------------------------------------------
 void CFormsView::OnTest()
 {
     form->put_me_on_you( "Employee", homer );   // Put the employee on
     form->interact(NULL, Rect(0,0,200,200));    // the form & display it.
 }
 //----------------------------------------------------------------------
 void CFormsView::OnReport() 
 {
     homer.print();
 }

Figure 6   Window and Button Classes

wrappers2.h


 // wrappers2.h:
 // 
 // This file is an extension of the Wrappers.h file discussed in Part
 // one of the article. It is included at the end of wrappers.h and
 // should not be included directly by you in your programs (include
 // wrappers.h instead). Were this not a two-part article, I would have
 // just put everything in the current file into wrappers.h and gotten
 // it over with.
 //
 // The following #if makes sure that wrappers2.h is being expanded
 // from within wrappers.h. The test fails if the #include occurs
 // anywhere else.
 
 #if (!defined(WRAPPERS_H__) || defined(WRAPPERS2_H_))
 #error Do not include wrappers2.h directly, include wrappers.h instead.
 #endif
 
 #define WRAPPERS2_H__
 //======================================================================
 // Window
 //======================================================================
 
 class Window: public CWnd
             , public Notifier
 {
     //{{AFX_VIRTUAL(Window)
     virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
     virtual void PostNcDestroy();
     //}}AFX_VIRTUAL
 
     //{{AFX_MSG(Window)
     //}}AFX_MSG
 
     DECLARE_MESSAGE_MAP()
 
 public:
     static const String no_title;
 
     Window( const Rect &position, const String &title    = no_title,
                             Notifiable *notify_on_close = &Nobody );
     virtual ~Window();
 
     void show( void );
     void hide( void );
 
     void destroy( void );
 private:
     Notifiable *notify_on_close;
 };
 //------------------------------------------------------------------------
 inline void Window::show( void )
 {
     ShowWindow( SW_SHOW );
 }
 //------------------------------------------------------------------------
 inline void Window::hide( void )
 {
     ShowWindow( SW_HIDE );
 }
 //------------------------------------------------------------------------
 inline void Window::destroy( void )
 {
     // A Window must be allocated from new. It is deleted automatically
     // when the user shuts down the window. DO NOT PASS THE Window POINTER
     // TO DELETE EVER. Instead, call p->destroy();
 
     DestroyWindow();
 }
 
 //======================================================================
 // Button
 //======================================================================
 
 class Button : public CButton
              , public Notifier
 {
 public:
     virtual ~Button(void);
     Button( const String &caption,    const Rect    &position,
             Notifiable    *notify = &Nobody );
 
     void show( Window *parent );
     void hide( void              );
 
 private:
     Notifiable *notify_on_press;
     String        caption;
     Rect        position;
 
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(Button)
     //}}AFX_VIRTUAL
     //{{AFX_MSG(Button)
 
     afx_msg void OnClicked();
     //}}AFX_MSG
 
     DECLARE_MESSAGE_MAP()
 };
wrappers2.cpp

 #include "stdafx.h"
 #include "wrappers.h"
 #include "notify.h"
 
 //======================================================================
 // Window
 //======================================================================
 const String Window::no_title;
 //----------------------------------------------------------------------
 /*virtual*/ Window::~Window(){}
 //----------------------------------------------------------------------
 Window::Window( const Rect     &position,
                 const String &title,            /*= no_title */
                 Notifiable     *notify_on_close    /*= &Nobody  */ )
 {
     this->notify_on_close = notify_on_close;
 
     // It's convenient to have a Create() function IN ADDITION to
     // PreCreateWindow(), but you must have PreCreateWindow too in case
     // someone calls CreateEx() or Create() polymorphically through a
     // CWnd pointer. Note that, since the current window is not a child
     // window, the position is screen relative, not parent-window relative.
     // 
     // Note that you can use CWnd::Create() to make a child window but
     // not a popup [Create() requires a be a parent window]. Since the
     // current example IS a popup, I must use CreateEx(), which is
     // a little more awkward to use, but more functional.
 
     #ifdef STD_DEBUG
         std_debug   << "Creating Window"
                     << "["          << title
                     << "] at "      << position
                     << " width="    << position.Width()
                     << " height="   << position.Height()
                     << "\n" ;
     #endif
 
     // Use CreateEx because this is a popup (Create() requires a parent
     // window). The class name is supplied by PreCreateWindow, as are
     // all attributes except the WS_CAPTION attribute. I add six units
     // to the window width to compensate for the border. If the window
     // has a caption bar (has_title is true), add 25 units for it and
     // the border, else just add 6 units for the border..
 
     bool has_title = &title != &no_title;
 
     CreateEx(    0,                // No extended attributes
                 NULL,
                 !has_title ? "": CString((String &)title),
                 !has_title ? 0 : WS_CAPTION,
                 position.left,
                 position.top,
                 position.Width()  + 6,
                 position.Height() + (has_title ? 25 : 6),
                 NULL,            // no parent 
                 NULL            // no menu
              );
 }
 //----------------------------------------------------------------------
 void Window::PostNcDestroy() 
 {
     // Called by the framework after the windows object has been
     // destroyed, frees the memory associated with the current window.
     // That is, I'm assuming that the window is allocated from new and
     // that it will stay around until the user opts to close it.
     // There will be no delete to match the new.
 
     notify( notify_on_close );
     CWnd::PostNcDestroy();
     delete this;
 }
 //----------------------------------------------------------------------
 BOOL Window::PreCreateWindow(CREATESTRUCT& cs) 
 {
     // Replace various arguments to Create (or CreateEx) with values
     // that are required by the current window implemenation. The
     // WS_VISIBLE attribute, though not strictly speaking necessary,
     // lets the caller dispense with the
     //                win->ShowWindow( SW_SHOWNORMAL );
     //                win->UpdateWindow();
     // calls.
 
     static CString class_name;
     if( class_name.IsEmpty() )
     {
         // If we haven't registered a class with Windows, yet, do it
         // for now. This call usually establishes cursor, brush, and
         // icon all windows of the current class. (Since the windows
         // isn't going to be minimized, I've left out the icon, here).
 
         HCURSOR    cursor    = AfxGetApp()->LoadStandardCursor( IDC_ARROW );
         HBRUSH    brush    = (HBRUSH) ::GetStockObject( WHITE_BRUSH );
         HICON    icon    = 0;
         class_name = AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW,
                                                 cursor,    brush,icon);
     }
 
     // Window is initially hidden, if that's not what
     // you want, OR WS_VISIBLE into the file bit.
 
     cs.style     |= WS_OVERLAPPED|WS_POPUPWINDOW ;
     cs.lpszClass = class_name;
     return CWnd::PreCreateWindow(cs);
 }
 //----------------------------------------------------------------------
 BEGIN_MESSAGE_MAP(Window, CWnd)
     //{{AFX_MSG_MAP(Window)
     //}}AFX_MSG_MAP
 END_MESSAGE_MAP()
 
 //======================================================================
 // Button
 //======================================================================
 /*virtual*/ Button::~Button(){}
 //----------------------------------------------------------------------
 Button::Button( const String &in_caption,
                 const Rect     &in_position,
                 Notifiable *notify /*=&Nobody*/): caption ( in_caption )
                                                 , position( in_position )
                                                 , notify_on_press(notify)
 {}
 
 void Button::show( Window *parent )
 {
     Create( (const CString)caption,
             WS_CHILD|WS_VISIBLE,
             position,
             parent,
             ~0U );                    // Button ID
 }
 
 void Button::hide( void )
 {
     DestroyWindow();
 }
 
 //----------------------------------------------------------------------
 void Button::OnClicked(void) 
 {
     notify( notify_on_press );
 }
 //----------------------------------------------------------------------
 BEGIN_MESSAGE_MAP(Button, CButton)
     //{{AFX_MSG_MAP(Button)
     ON_CONTROL_REFLECT(BN_CLICKED, OnClicked)
     //}}AFX_MSG_MAP
 END_MESSAGE_MAP()

Figure 7   Final Form Classes

form.h


 // form.h
 #ifndef FORM_H__
 #define FORM_H__
 
 #include "mystring.h"    // Discussed in Part 1.
 #include "userintf.h"    // Discussed in Part 1.
 #include "wrappers.h"    // Discussed in Part 1.
 
 // Notes:
 // (*)    The Form::fields member is an array for the time
 //        being, it should really be variable-length collection.
 //
 // (*)    Forms cannot be copied, so the operator= and copy ctor are
 //        private. There's not need to define the functions, simple
 //        prototypes are sufficient. (The linker kicks out an error
 //        if the function isn't defined and someone manages to call
 //        it.)
 
 class Form : public     User_interface
 {
 public:
     class Field;        // These classes are nested inside the Form
     class Element;      // class's name space, not external
     class Proxy;        // references. Definitions are below.
     class Close_button;
 
 public:    
     virtual
     ~Form( void    );
      Form( const String &form_name, Field *first, ... );
 
 private:
     Form               ( const Form &r );    // do not define
     Form &operator=    ( const Form &r );    // do not define
 
 public:
     bool add_field            ( Field *new_field            );
     void release_proxies      ( void                        );
     void put_me_on_you        ( const String  &class_name,
                                 const Element &ele        );
     void remove_me_from_you   ( const String  &class_name    );
 
 public: // overrides for User_interface base class
     virtual void hide     ( void                          );
     virtual bool display  ( Window *win, const Rect &rect );
     virtual bool interact ( Window *win, const Rect &rect );
 
 
 private:
     String        name;
     Rect        size;
     Form::Field **current;
 
     enum { max_fields = 32 };
     Form::Field    *fields[max_fields];// fields on the form, should be a
                                     // "collection" instead of an array.
 
     // Create an internal class so that the Window can notify us
     // when we're destroyed. Make it a friend so that it can release
     // the proxies.
 
     class Destroyer: public Notifiable
     {
         Form *form;
         virtual void notify( class Notifier *sender );
     public:
         Destroyer(Form *notifiee): form(notifiee) {}
     }
     destroyer;
     friend class Form::Destroyer;
 
 public:
     void debug_print(void);
 };
 
 #if (defined(NDEBUG) || !defined(STD_DEBUG)) // not debuggging
     inline void Form::debug_print(void){}
 #endif
 
 //-------------------------------------------------------------------
 // Form::Field
 //
 // It is a serious error for the same attribute proxy to be used in
 // more than one form. This problem can be solved by reference-
 // counting the proxy, but is not solved in the current implementation.
 //
 // A Field can't be copied.
 
 class Form::Field: public User_interface
 {
 public:
     enum Behavior{ input_output=0, input=0, output=1 };
 
     virtual
     ~Field( void                                        );
      Field(          User_interface *static_attrib,
             const Rect             &position            );
      Field( const String           &class_name,
             const String           &attribute_id,
             const Rect             &position,
             const Behavior         behavior= input_output );
 
 private:
      Field                    (const Field &); // Do not define.
      const Field &operator=    (const Field &);
 
 public:
     const String *if_in_class_return_id (const String   &cls_name)const;
     void         attach_proxy            (Proxy            *proxy   );
     void         release_proxy            (void                     );
 
 public: // overrides for User_interface base class
     virtual void hide     ( void                             );
     virtual bool display ( Window *win, const Rect &rect );
     virtual bool interact( Window *win, const Rect &rect );
 
 private:
     Behavior     mode;
     String       class_name;
     String       attribute_id;
     Rect         position;
     Proxy        *proxy;    // Supplied by Form::Element if not
                             // static, otherwise comes from user
                             // via Form::Form or Form::add_field.
 private: friend class Form;
     const Rect    &size( void );
 
     friend void Form::debug_print(void);
 };
 //-------------------------------------------------------------------
 class Form::Proxy : public User_interface
 {
 public:
      virtual
     ~Proxy(void);
      Proxy(    User_interface *attribute_proxy,
             Element           *notify_me_rather_than_delete_proxy = NULL);
 
     void release(void);
 
 public: // overrides for User_interface base class
     virtual void hide     ( void                             );
     virtual bool display ( Window *win, const Rect &rect );
     virtual bool interact( Window *win, const Rect &rect );
 
 protected:    User_interface    *ui;
 private:    Form::Element    *creator;
 
             friend void Form::debug_print(void);
 };
 
 //-------------------------------------------------------------------
 // Elements can be copied, but there's nothing to copy at this level,
 // so leave it up to the derived class. Note that, even though
 // give_me_a_proxy_for(...) doesn't modify the class, it is not
 // const because the returned proxy could modify the class.
 
 class Form::Element
 {
 public:
     virtual ~Element(void);
 
 private: friend class Form;
     virtual Proxy *give_me_proxy_for(const String &form_name,
                                      const String &attribute_id )=0;
 private: friend class Proxy;
     virtual void release_proxy(Proxy *p);
 
     friend void Form::debug_print(void);
 };
 //----------------------------------------------------------------------
 class Form::Close_button: public User_interface
                         , public Notifiable
 {
     Button *button;
     Window *parent;
 public:
     virtual
     ~Close_button(void);
      Close_button(void);
 
     virtual void hide     ( void                                 );
     virtual bool display ( Window *win, const Rect &position );
     virtual bool interact( Window *win, const Rect &position );
     
     virtual void notify     ( class Notifier *sender             );
 
     friend void Form::debug_print(void);
 };
 //----------------------------------------------------------------------
 #endif FORM_H__
form.cpp

 // form.cpp
 
 #include "stdafx.h" // Needed only to keep compiler happy
 #include "form.h"
 #include <stdarg.h>
 //===================================================================
 // Form
 //===================================================================
 /*virtual*/ Form::~Form( void )
 {
     assert( this );
 
     // Delete the fields, first releasing the proxies
 
     for(Field **p=fields; p < &fields[max_fields] && *p ;)
     {
         (*p)->release_proxy();
         delete( *p++ );
     }
 }
 //-------------------------------------------------------------------
 // The initializer-list element "observer(this)" causes the compiler
 // to kick out a:
 //
 // warning C4355: 'this' : used in base member initializer list.
 //
 // Normally, it would be dangerous for the contained-object
 // constructor to access the container class because the contained
 // objects are initialized before the container is initialized.
 // We don't do that here, and it's convient to pass a pointer
 // to the container at construction time, so turn off the warning.
 
 #pragma warning( disable : 4355 )
 
 Form::Form( const String &form_name, Field *first, ... )
                     : current    ( fields     )
                     , name        ( form_name     )
                     , size        ( 0, 0, 0, 0 )
                     , destroyer    ( this         )
 {
     // Initialize the Form with its name and fields. Any
     // fields in excess of max_fields are silently discarded.
     //
     // There's nothing wrong with any function (including a constructor)
     // having a variable number of arguments. The argument passed
     // to va_start MAY NOT be a reference, however becuase taking
     // the address of the reference gets you the referenced thing.
 
     va_list    field_list;
     va_start( field_list, first );
 
     memset( fields, 0, sizeof(fields) );
 
     Field *field = first;
     while( field && (current < &fields[max_fields]) )
     {
         size.expand_to_include( field->size() );
         *current++ = field;
         field = va_arg(field_list, Field *);
     }
 
     va_end( field_list );
 }
 
 #pragma warning( default : 4355 )
 //-------------------------------------------------------------------
 bool Form::add_field( Field *new_field    )
 {
     assert( this      );
     assert( new_field );
 
     if( current < &fields[max_fields] )
     {
         *current++ = new_field;
         size.expand_to_include( new_field->size() );
         return true;
     }
     return false;
 }
 //-------------------------------------------------------------------
 void Form::release_proxies( void )
 {
     assert( this );
 
     Field **current = fields;    
     while( current < &fields[max_fields] && *current )
         (*current++)->release_proxy();
 }
 //-------------------------------------------------------------------
 void Form::put_me_on_you( const String     &class_name,
                           const    Element &element )
 {
     assert( this         );
     assert( &element     );
     assert( &class_name     );
 
     Field **current = fields;    
     for(; current < &fields[max_fields] && *current; ++current )
     {
         const String *id = (*current)->if_in_class_return_id(class_name);
         if( id )
         {
             Element &e    = (Element &)element;
             Proxy *p    = e.give_me_proxy_for( name, *id );
             if( p )
                 (*current)->attach_proxy( p );
         }
     }
 }
 //-------------------------------------------------------------------
 void Form::remove_me_from_you( const String &class_name )
 {
     assert( this         );
     assert( &class_name     );
 
     // Remove all proxies on fields associated with given class_name
 
     Field **current = fields;    
     for(; current < &fields[max_fields] && *current; ++current )
     {
         if( (*current)->if_in_class_return_id(class_name) )
             (*current)->release_proxy();
     }
 }
 //-------------------------------------------------------------------
 /*virtual*/ void Form::hide( void )
 {
     assert( this         );
 
     Field *const *current = fields;    
     while( current < &fields[max_fields] )
         (*current++)->hide();
 }
 //-------------------------------------------------------------------
 /*virtual*/ bool Form::display( Window *win, const Rect &rect )
 {
     assert( this     );
     assert( win         );
     assert( &rect     );
 
     // Display the form, either on the indicated Window or on a
     // manufactured popup window if win is NULL. The Rect argument
     // is ignored. (Note that, since the Field's display and interact
     // handlers also ignore the rect argument, I just pass it through
     // to avoid having to create a dummy rectangle).
     //
     // If a popup window is created, the form name is used for the
     // title and the windows size is exactly large enough to hold
     // all fields.
 
     Window *surface= win ? win
                          : new Window(size, name, &destroyer) ;
 
     Field *const *current = fields;
     while( current < &fields[max_fields] )
         (*current++)->display(surface, rect);
     return true;
 }
 //-------------------------------------------------------------------
 /*virtual*/ bool Form::interact( Window *win, const Rect &rect )
 {
     assert( this    );
     assert( &rect    );
 
     // See comments in display() function, above.
     Window *surface = win ? win : new Window(size, name, &destroyer);
     surface->show();
 
     Field **fieldv = fields;    
     while( *fieldv &&  (fieldv < &fields[max_fields]) )
         (*fieldv++)->interact(surface, rect);
 
     return true;
 }
 //-------------------------------------------------------------------
 #if !defined(NDEBUG) && defined(STD_DEBUG)
 #include "text.h"
 
 void Form::debug_print(void)
 {
     std_debug << "Form @" << this
               << " name[" << name << "]"
               << " size"  << size
               << " fields:\n" ;
 
     Field **fieldv = fields;    
     for(; *fieldv &&  (fieldv < &fields[max_fields]) ; ++fieldv)
     {
         std_debug << "   Field["<< (fieldv-fields)            << "]";
         std_debug << " class("    << (*fieldv)->class_name    << ")";
         std_debug << " attrib("    << (*fieldv)->attribute_id    << ")";
         std_debug << " posn"    << (*fieldv)->position        << ")";
         std_debug << " proxy @" << (*fieldv)->proxy    ;
         if( (*fieldv)->proxy )
         {
             std_debug << " crtr @"    << (*fieldv)->proxy->creator ;
             
             Text *text = dynamic_cast<Text *>( (*fieldv)->proxy->ui );
             if( text )
                 std_debug << " Text(\"" << *text << ")\n" ;
 
             else if( dynamic_cast<Form::Close_button *>( (*fieldv)->proxy->ui ) )
                 std_debug << "(close button)\n";
             else
                 std_debug << "***UNKNOWN PROXY***" ;
         }
         std_debug << "\n";
     }
 }
 #endif
 //===================================================================
 // Form::Destroyer
 //===================================================================
 /*virtual*/ void Form::Destroyer::notify( class Notifier *sender )
 {
     // This function is called when the window that the form is
     // using as its drawing surface is shut down by the user. It
     // destroys the associated Form, which causes the proxies to
     // be released.
 
     assert( dynamic_cast<Window*>(sender) );
     delete form;
 }
 //===================================================================
 // Form::Field
 //===================================================================
 /*virtual*/ Form::Field::~Field( void )
 {
 }
 //-------------------------------------------------------------------
 #include "text.h"
 Form::Field::Field( User_interface    *static_attrib,
                     const Rect         &position_in )
             : mode            ( output )
             , class_name    ( "" )
             , attribute_id    ( "" )
             , position        ( position_in    )
             , proxy            ( new Proxy(static_attrib) )
 {
     #if (!defined(NDEBUG) && defined(STD_DEBUG))
         std_debug << "Adding static_attrib @" << static_attrib << "\n";
     
         Text *txt = dynamic_cast<Text*>(static_attrib);
         if( txt )
         {
             std_debug << "\t(value is " << *txt << " @" << txt << ")\n" ;
             return;
         }
     #endif
 }
 //-------------------------------------------------------------------
 Form::Field::Field( const String    &class_name_in,
                     const String    &attribute_id_in,
                     const Rect        &position_in,
                     const Behavior    mode_in /*= input_output */ )
             : mode            ( mode_in            )
             , class_name    ( class_name_in        )
             , attribute_id    ( attribute_id_in    )
             , position        ( position_in        )
             , proxy            ( NULL                )
 {
 }
 //-------------------------------------------------------------------
 const String *Form::Field::
 if_in_class_return_id(const String &candidate )const
 {
     assert( this        );
     assert( &candidate    );
 
     return (class_name == candidate) ? &attribute_id : NULL;
 }
 //-------------------------------------------------------------------
 void Form::Field::attach_proxy(Proxy *proxy)
 {
     assert( this              );
     assert( proxy              );
     assert( this->proxy==NULL ); // Illegal if a proxy already attached
 
     this->proxy = proxy;
 }
 //-------------------------------------------------------------------
 // Note for release_proxy, hide, display, interact. It's not an error
 // if a field that doesn't have a proxy attached to itself is displayed,
 // etc. It's just a no-op.
 //
 void Form::Field::release_proxy(void)
 {
     assert( this );
 
     if( proxy )
         proxy->release();
     proxy = NULL;
 }
 //-------------------------------------------------------------------
 /*virtual*/ void Form::Field::hide( void )
 {
     assert( this    );
 
     if( proxy )
         proxy->hide();
 }
 //-------------------------------------------------------------------
 /*virtual*/ bool Form::Field::display( Window *win, const Rect &rect )
 {
     assert( this    );
     assert( win        );
     assert( &rect    );
     
     return proxy ? proxy->display( win, rect ) : true;
 }
 //-------------------------------------------------------------------
 /*virtual*/ bool Form::Field::interact( Window *win, const Rect &rect )
 {
     // Display the current field. The rect argument is ignored in
     // favor of the position rectangle stored in the Field itself.
 
     assert( this  );
     assert( win      );
     assert( &rect );
     assert( proxy );
 
     return    (proxy==NULL  ) ? true :
             (mode == input)    ? proxy->interact( win, position ) :
                               proxy->display ( win, position ) ;
 }
 //-------------------------------------------------------------------
 const Rect &Form::Field::size( void )
 {
     // Normally, I wouldn't return a reference to a field in an object
     // because the caller could modify the field. Here, it seems safe
     // because the fuction is private, and called only from the Form
     // class.
 
     return position;
 }
 //===================================================================
 // Form::Proxy
 //===================================================================
 /*virtual*/ Form::Proxy::~Proxy(void){}
 //-------------------------------------------------------------------
 Form::Proxy::Proxy(    User_interface *attribute,
                     Form::Element  *notify_me_rather_than_delete_proxy )
         : ui        ( attribute    )
         , creator    ( notify_me_rather_than_delete_proxy /*=NULL*/ )
 {}
 //-------------------------------------------------------------------
 void Form::Proxy::release( void )
 {
     assert( this );
 
     if( creator )
         creator->release_proxy(this);
     else
     {
         if( ui )
             delete ui;
         delete this;
     }
 }
 //-------------------------------------------------------------------
 /*virtual*/ void Form::Proxy::hide( void )
 {
     assert( this );
     assert( ui     );
     ui->hide();
 }
 //-------------------------------------------------------------------
 /*virtual*/ bool Form::Proxy::display( Window *win, const Rect &rect )
 {
     assert( this );
     assert( ui     );
     return ui->display( win, rect );
 }
 //-------------------------------------------------------------------
 /*virtual*/ bool Form::Proxy::interact( Window *win, const Rect &rect )
 {
     assert( this );
     assert( ui     );
     return ui->interact( win, rect );
 }
 //===================================================================
 // Form::Element
 //===================================================================
 /*virtual*/ Form::Element::~Element(void){}
 //-------------------------------------------------------------------
 /*virtual*/ void Form::Element::release_proxy(Proxy *p)
 {
     // Empty on purpose. The default action is to not release
     // anything. The derived class can define an override if it
     // provides proxies that need to be released.
 }
 //===================================================================
 // Form::Close_button
 //===================================================================
 Form::Close_button::~Close_button(){ if(button) delete button; }
 Form::Close_button::Close_button() : button(NULL), parent(NULL){}
 //-------------------------------------------------------------------
 /*virtual*/ 
 void Form::Close_button::hide( void )
 {
     assert( this );
     if( button )
     {
         delete button;
         button = NULL;
     }
 }
 //-------------------------------------------------------------------
 /*virtual*/ 
 bool Form::Close_button::display( Window *win, const Rect &position )
 {
     assert(this);
     assert(win );
     assert(&position);
 
     parent = win;
     button = new Button( "Close", position, this );
     button->show(win);
     return true;
 }
 //-------------------------------------------------------------------
 /*virtual*/ 
 bool Form::Close_button::interact( Window *win, const Rect &position )
 {
     return display(win, position);
 }
 //-------------------------------------------------------------------
 /*virtual*/
 void Form::Close_button::notify( class Notifier *sender )
 {
     // This function is called when the window that the form is
     // using as its drawing surface is shut down by the user. It
     // destroys the associated Form, which causes the proxies to
     // be released.
 
     Button *b = dynamic_cast<Button*>(sender);
     assert(b);
     assert(b==button);
     assert(parent);
     parent->DestroyWindow();
 }