\documentstyle[camera,code,psfig,twoside]{article}
\clubpenalty=10000
\hyphenpenalty=1000
\exhyphenpenalty=5000
\widowpenalty=10000

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}

%\psdraft

\title{ 
    Unidraw Tutorial I: \\
    A Simple Drawing Editor
}

\author{
    John Vlissides \\
    Stanford University \\[1em]
    \small Draft of \today
}

\maketitle
\thispagestyle{empty}
\renewcommand{\thefootnote}{}
\footnotetext{
    Research supported by a grant from Fujitsu America, Inc., by the
    NASA CASIS project under Contract NAGW 419, and by the Quantum
    project through a gift from Digital Equipment Corporation.
}
\renewcommand{\thefootnote}{\arabic{footnote}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{abstract}

This is the first in a series of tutorials on Unidraw, a library of
classes designed to simplify the implementation of graphical editors.  This
tutorial focuses on the implementation of a bare-bones drawing editor
based on the Unidraw library.  The tutorial discusses the application's
design and implementation in detail.

\end{abstract}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Introduction}

Unidraw is a library of classes that support the construction of
direct-manipulation graphical editors.  Unidraw defines abstractions
that are geared to the special requirements of such applications to
reduce the effort needed to create them. This tutorial describes the
implementation of a simple drawing editor called {\bf punidraw}, which
is built with Unidraw.  Punidraw lets a user create and arrange lines,
rectangles, and ellipses to form drawings.  The user can move these
objects around, scale, rotate, duplicate, and delete them.  Punidraw
has several features that make editing easier, including scrolling and
zooming facilities and multi-level undo and redo.  The user can create
a PostScript version of the drawing and send it to a printer, and he
can save the drawing in a file for editing later.

These tutorials assume you have access to the library and its
documentation~\cite{interviews:man}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Interface}

\begin{figure}[t]
\centerline{\psfig{figure=figs/punidraw.ps,width=3in}}
\caption{Punidraw interface}
\label{punidraw screen dump}
\end{figure}

Figure~\ref{punidraw screen dump} shows punidraw's interface.  The
large rectangular region in the center is the {\bf drawing area}, in
which the user creates and edits drawings. Along the right side of the
drawing area is a palette of tools for creating and manipulating
graphical objects by direct manipulation. From top to bottom, these
tools are:
\begin{itemize}

\item {\bf Select}, for selecting existing graphical
objects. Selected objects are surrounded by several small filled
rectangles called {\bf handles}.

\item {\bf Move}, for moving objects from one position to another.

\item {\bf Scale}, for scaling objects about their centers.

\item {\bf Rotate},  for rotating objects about their centers.

\item {\bf Line}, for creating line objects.

\item {\bf Rectangle}, for creating rectangles.

\item {\bf Ellipse}, for creating ellipses.

\end{itemize}
A user draws by creating lines, rectangles, and ellipses in the
drawing area with their respective tools {\bf engaged}.  A tool is
engaged when its icon appears highlighted in the tool palette.  To
draw a line, for example:
\begin{enumerate}

\item Engage the line tool.

\item Click in the drawing area with the left mouse button to specify
the line's first endpoint.

\item {\bf Drag} the mouse (i.e., move it with the left button still
depressed) to the location of the second endpoint.  Punidraw will draw
a line from the first endpoint to the current mouse to suggest the
line's ultimate appearance.

\item Release the left button to anchor the second endpoint.

\end{enumerate}
Rectangle or ellipse creation follows the same downclick-drag-upclick
procedure but with different visual feedback.  The user can select,
move, scale, or rotate an existing graphical object by clicking on it
with the corresponding tool engaged.  Each tool generates distinctive
visual feedback to suggest how it affects the object.

Below the tool palette is a {\bf panner}, an interface for scrolling
the drawing area horizontally and vertically and for changing its
current magnification. Along the top are two pull-down menus
containing {\bf commands} for performing various operations.  The
``File'' menu provides operations for clearing the drawing area ({\bf
New}), opening a new drawing ({\bf Open}), saving the current drawing
({\bf Save}), printing the drawing ({\bf Print}), and quiting the
application ({\bf Quit}). The ``Edit'' menu contains choices for
undoing and redoing previous commands ({\bf Undo} and {\bf Redo}) and
for deleting and duplicating selected objects ({\bf Delete} and {\bf
Duplicate}).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Code Organization}
\label{code organization}

The code that implements punidraw is organized into three files:
\begin{enumerate}

\item {\tt main.c} contains the main program.

\item {\tt pued.h} declares the Punidraw class, which define
punidraw's interface.

\item {\tt pued.c} implements the class declared in {\tt pued.h}.

\end{enumerate}

\begin{figure}[t]
\begin{code}{0em}
#include "pued.h"

#include <Unidraw/catalog.h>
#include <Unidraw/creator.h>
#include <Unidraw/unidraw.h>

#include <InterViews/world.h>

static PropertyData properties[] = {
  { "*domain",  "drawing" },
  { "*history",	"20" },
  { nil }
};

static OptionDesc options[] = {
  { nil }
};

int main (int argc, char** argv) {
  Creator creator;
  Unidraw* unidraw = new Unidraw(
    new Catalog(
      "punidraw", &creator
    ), argc, argv, options, properties
  );

  unidraw->Open(new Punidraw);
  unidraw->Run();

  delete unidraw;
  return 0;
}
\end{code}
\caption{{\tt main.c}}
\label{main.c}
\end{figure}

Figure~\ref{main.c} shows the code in {\tt main.c}.  Below the {\tt
\#include} directives at the top are two static arrays that specify a
default set of properties and command line options.  We have specified
values for two standard Unidraw properties:
\begin{enumerate}
\item The {\bf domain} property is a short name for the drawings
that the application creates.

\item The {\bf history} property specifies the length of the undo
history list for the application.

\end{enumerate}
Punidraw supports no special command line options, so the OptionDesc
array is left empty.

Every Unidraw application must instantiate a {\bf Unidraw} object,
which defines the program's main loop and manages other aspects of its
operation.  The Unidraw object in turn requires an instance of a {\bf
Catalog} object, which provides an interface for saving and retrieving
Unidraw objects.  Unidraw's constructor also takes argc and argv plus
the static arrays we've already described containing property and
command line option information.

The catalog must be passed a string name (``punidraw'' in this case)
which it may use to distinguish this application's objects from those
of other Unidraw applications.  We also pass the catalog a {\bf
Creator} object with which to construct objects just prior to reading
them from disk.  Applications that define new subclasses of Unidraw
objects that can be saved and retrieved must also extend Creator (via
subclassing) to create these new classes.  In our case, however, we
can simply pass an instance of the Creator base class, because
punidraw does not define any such subclasses.

Once there's a unidraw object, we can create an instance of the
Punidraw class, which defines punidraw's interface.  We'll discuss
this class at length in subsequent sections.  We can make punidraw's
interface appear on the display by telling the unidraw object to {\bf
Open} the punidraw instance.  The {\bf Run} operation encapsulates the
application's main loop and brings punidraw's interface to life.  Run
will return after the user quits the application. Then the main
program deletes the Unidraw object and returns the program's exit
status.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Punidraw Class Declaration}

Figure~\ref{Punidraw class declaration} shows the declaration for the
Punidraw class, the only derived class in the application.  Punidraw
is derived from {\bf Editor}, an abstract class for top-level windows
in Unidraw applications.  Editors assemble basic toolkit objects (like
buttons, scroll bars, and menus) and other Unidraw objects (like
viewers, panel controls, and state variable views) into a complete
user interface through which to manipulate application data.  An
application may define more than one kind of editor and can present
multiple editor instances at a time to the user.

\begin{figure}[t]
\begin{code}{0em}
class Punidraw : public Editor {
public:
  Punidraw(GraphicComp* = nil);
  virtual ~Punidraw();

  virtual Component* GetComponent();
  virtual Viewer* GetViewer(int = 0);
  virtual KeyMap* GetKeyMap();
  virtual Tool* GetCurTool();
  virtual Selection* GetSelection();

  virtual void SetComponent(Component*);
  virtual void SetViewer(Viewer*, int = 0);
  virtual void SetKeyMap(KeyMap*);
  virtual void SetSelection(Selection*);
private:
  Interactor* Interior();
  void InitViewer();

  Interactor* Commands();
  Interactor* Tools();

  void Include(
    class Command*, class PulldownMenu*
  );
  void Include(Tool*, class Box*);

  PulldownMenu* FileMenu();
  PulldownMenu* EditMenu();
private:
  GraphicComp* _comp;
  KeyMap* _keymap;
  class ControlState* _curCtrl;
  Viewer* _viewer;
  Selection* _selection;
};
\end{code}
\caption{Punidraw class declaration}
\label{Punidraw class declaration}
\end{figure}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \subsection{Public Member Functions}

The Punidraw constructor takes an optional graphical component subject
({\bf GraphicComp}) as an argument.  This is the object that the
editor will present to the user for editing.  The destructor will
delete objects that the editor creates.

Punidraw redefines several operations declared in the Editor base
class for setting and getting information that the editor keeps and
that other Unidraw objects may need to access. {\bf GetComponent}
simply returns the component that the editor edits; in this case, it
will be a graphic component. What the user sees and manipulates in
punidraw are actually children of this component---instances of line,
rectangle, or ellipse components.  Conversely, {\bf SetComponent}
changes the component that the editor edits to another component.

{\bf GetViewer} is an Editor operation that should be redefined to
return the viewer(s) in the editor. Unidraw's {\bf Viewer} class
defines an object that displays a graphical component (and its
children) in a window.  It furnishes the drawing area in punidraw's
interface.  Viewers supports scrolling and zooming their component in
addition to simply displaying it.  An editor's Viewer instances are
referred to by integer index, and GetViewer returns the appropriate
viewer given its index.  Like most applications, punidraw's interface
contains just one viewer, which has index 0 by convention.  {\bf
SetViewer} changes the {\em n}th viewer in the editor to the one
supplied as an argument.

Editor subclasses usually redefine {\bf GetKeyMap} to return a {\bf
KeyMap} object. Keyaps implement the application's keyboard
accelerators such as control-O for Open, etc.  We'll redefine this
operation to return the keymap created in the Punidraw constructor.
{\bf SetKeyMap} changes Punidraw's keymap.

{\bf GetCurTool} returns whatever {\bf Tool} object is currently
engaged.  Tools are Unidraw objects that support direct manipulation
of components. When the user clicks in the viewer, he will be using
the tool that this operation returns.  In Punidraw this could be an
instance of {\bf SelectTool}, {\bf MoveTool}, {\bf ScaleTool}, {\bf
RotateTool}, or {\bf GraphicCompTool}.  The editor can store the
current tool in any convenient form. We'll chose to store it in an
InterViews {\bf ControlState} object, to which we can attach buttons
that let the user change the current tool.  In fact, we'll make that
the {\em only} way to change the current tool by not even defining
{\bf SetCurTool.}

Editors maintain a list of components that are currently selected.
Instances of Unidraw's {\bf Selection} class store this information.
{\bf GetSelection} should return the editor's selection object, and
{\bf SetSelection} should change it.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \subsection{Private Member Functions}

The Punidraw class defines several private member functions that the
public functions use to better structure their code. {\bf Interior}
creates the interactor composition that defines punidraw's look and
feel. {\bf InitViewer} creates and initializes the viewer:  It
creates a view of the component that the editor edits and places it
in the viewer.

{\bf Commands} is a helper function that creates the application's
commands and puts them in pull-down menus.  It returns an interactor
composition that contains punidraw's File and Edit menus. {\bf Tools}
returns a composition containing interactors for engaging the current
tool. This composition implements the palette of tools along the right
side of punidraw's interface.

There are two {\bf Include} operations that help build the menu and
palette compositions. The first takes a {\bf Command} instance and a
{\bf PulldownMenu} instance. A command is not an interactor; it is a
Unidraw object that merely executes some code when called upon to do
so.  This Include function wraps the command up in a {\bf
CommandControl}, which is an interactor that invokes the command when
user upclicks on it.  Then Include places the command control into the
pull-down menu.  

The second Include operation takes a tool object and a box.  Like
commands, tools have no look and feel for engaging them.  The second
Include function wraps the tool in a {\bf PanelControl}, an interactor
that acts like a radio button but can have varied appearances.  Then
it inserts the panel control into the box.  The Tools function uses
this version of Include to compose the palette of tools.

The last two private member functions, {\bf FileMenu} and {\bf
EditMenu} simply build up the corresponding pull-down menus.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \subsection{Private Member Variables}

The last part of the Punidraw class declaration specifies private
member variables for storing the editor's state.  Punidraw's public
Set/Get operations access these members.

The editor's graphical component is stored in the {\bf \_comp} member.
The {\bf \_keymap} member stores the keymap.  {\bf \_curCtrl} is
the control state that keeps track of the current tool.  The editor's
viewer is stored in the {\bf \_viewer} member, and the current
selection is stored in {\bf \_selection}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Punidraw Class Implementation}

\begin{figure}
\begin{code}{0em}
#include "pued.h"

#include <Unidraw/classes.h>
#include <Unidraw/ctrlinfo.h>
#include <Unidraw/keymap.h>
#include <Unidraw/kybd.h>
#include <Unidraw/page.h>
#include <Unidraw/selection.h>
#include <Unidraw/uctrls.h>
#include <Unidraw/viewer.h>

#include <Unidraw/Commands/catcmds.h>
#include <Unidraw/Commands/edit.h>

#include <Unidraw/Components/ellipse.h>
#include <Unidraw/Components/line.h>
#include <Unidraw/Components/rect.h>

#include <Unidraw/Graphic/ellipses.h>
#include <Unidraw/Graphic/lines.h>
#include <Unidraw/Graphic/polygons.h>

#include <Unidraw/Tools/grcomptool.h>
#include <Unidraw/Tools/move.h>
#include <Unidraw/Tools/rotate.h>
#include <Unidraw/Tools/scale.h>
#include <Unidraw/Tools/select.h>

#include <InterViews/border.h>
#include <InterViews/glue.h>
#include <InterViews/menu.h>
#include <InterViews/panner.h>
#include <InterViews/world.h>
\end{code}
\caption{Files included by {\tt pued.c}}
\label{headers}
\end{figure}

This section describes the Punidraw object's implementation in detail.
As mentioned in Section \ref{code organization}, {\tt pued.h} contains
the code that implements the Punidraw class.  Figure~\ref{headers}
shows the files that {\tt pued.c} includes to declare the objects it
uses.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \subsection{Constructor and Destructor}

\begin{figure}
\begin{code}{0em}
Punidraw::Punidraw (GraphicComp* comp) {
  SetClassName("Punidraw");

  _comp = (comp == nil) ?
    (new GraphicComps) : comp;
  _keymap = new KeyMap;
  _curCtrl = new ControlState;
  _selection = new Selection;

  InitViewer();
  Insert(Interior());
  GetKeyMap()->Execute(CODE_SELECT);
}
\end{code}
\caption{Punidraw constructor}
\label{Punidraw ctor}
\end{figure}

Punidraw's constructor definition is shown in Figure~\ref{Punidraw
ctor}. Punidraw is derived from Editor, which is a kind of interactor.
Like all interactors, Punidraw must define a class name to identify
itself to InterViews' Xdefaults mechanism. Therefore the constructor
first sets Punidraw's class name to ``Punidraw.''

The constructor then initializes four of the class' member variables.
It initializes the \_comp member with the component instance passed to
the constructor; if no such component was supplied, then it uses a
{\bf GraphicComps} instance. GraphicComps is a kind of GraphicComp
that can have children. The graphical component instances (i.e.,
lines, rectangles, and ellipses) that the user creates in Punidraw
become the children of this component.

Next, the constructor creates a new keymap for the keyboard
accelerators, the control state that stores the tool that's engaged
currently, and the editor's Selection instance. The subsequent call
to InitViewer initializes the viewer, in which the user views and
manipulates drawings. The second-to-last operation defines Punidraw's
user interface:  the Interior operation creates an interactor composition
that gives punidraw its look and feel, and the Insert operation inserts
this composition into the Punidraw object as its sole component.  Finally,
the constructor engages the Select tool so that it will be engaged
by default when punidraw starts up.  We do this by telling the keymap
to execute the keyboard equivalent, which we'll discuss further in
Section~\ref{defining appearance}.

\begin{figure}
\begin{code}{0em}
Punidraw::~Punidraw () {
  delete _keymap;
  delete _selection;
}
\end{code}
\caption{Punidraw destructor}
\label{Punidraw dtor}
\end{figure}

The destructor, shown in Figure~\ref{Punidraw dtor}, deletes only the
keymap and the selection instances explicitly.  There is no need (in
fact, it's {\em wrong}) to delete the editor's component, as that's
the unidraw object's responsibility.  There's also no need to delete
the viewer or control state instances. They're associated with
punidraw's interactor composition, so they'll be deleted in the parent
class (i.e., MonoScene) destructor.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \subsection{Access Functions}

\begin{figure}
\begin{code}{0em}
Component* Punidraw::GetComponent () { 
  return _comp;
}

Viewer* Punidraw::GetViewer (int id) {
  return (id == 0) ? _viewer : nil;
}

KeyMap* Punidraw::GetKeyMap () {
  return _keymap; 
}

Selection* Punidraw::GetSelection () {
  return _selection;
}

Tool* Punidraw::GetCurTool () {
  UControl* c =
    (UControl*) _curCtrl->Selection();
  return 
    (Tool*) c->GetControlInfo()->GetOwner();
}
\end{code}
\caption{State-returning access functions}
\label{get functions}
\end{figure}

Figure~\ref{get functions} shows the implementation of Punidraw's
state-returning access functions, most of which simply return the
corresponding member variable.  SetViewer includes a sanity check to
make sure the user specifies the one and only viewer (i.e., the
``zero-th'' viewer).  GetCurTool is more complicated than the others
because it must extract the current tool instance from the control
state, which stores the control that is highlighted currently.  For
example, the panel control labeled ``Select'' highlights itself when
the Select tool is engaged.

Unidraw applications use PanelControl instances to engage the current
tool and CommandControl instances to execute commands from menus.
Both PanelControl and CommandControl are derived from {\bf UControl},
a subclass of InterViews' {\bf Control} class specialized for Unidraw.
UControls have a particular icon or command equivalence, and they
store that information in a {\bf ControlInfo} object.  It is the
ControlInfo that distinguishes UControls from vanilla InterViews
controls.

ControlInfo typically defines its appearance with two pieces of text,
one for the menu entry and another for the keyboard equivalent.  More
generally, however, it can have a graphical component define its
appearance.  For example, punidraw's panel controls for the line,
rectangle, and ellipse creation tools use corresponding graphical
components to identify their function iconically. A ControlInfo also
defines an {\bf owner}, which defines the command or tool that the
control controls.  ControlInfo's {\bf GetOwner} operation returns a
{\tt void*}, which in the context of the GetCurTool operation is
actually a pointer to a tool instance. GetOwner returns a {\tt void*}
because there is no common base class for tools and commands, but
normally one deals with either one or the other.

\begin{figure}
\begin{code}{0em}
void Punidraw::SetComponent (
  Component* comp
) {
  if (comp == nil || comp->IsA(GRAPHIC_COMP)) {
    _comp = (GraphicComp*) comp;
  }
}

void Punidraw::SetViewer (Viewer* v, int i) { 
  if (i == 0) {
    _viewer = v;
  }
}

void Punidraw::SetKeyMap (KeyMap* k) {
  _keymap = k;
}

void Punidraw::SetSelection (Selection* s) {
  _selection = s;
}
\end{code}
\caption{State-setting access functions}
\label{set functions}
\end{figure}

Figure~\ref{set functions} shows the implementations of the
corresponding state-setting access functions. SetComponent changes the
component that the editor edits.  Editors generally edit components,
but not necessarily {\em graphical} components.  SetComponent
therefore adds a safety test that verifies that the component is
graphical before accepting it. SetViewer also has a safety check to
make sure the caller specifies a valid index.  Finally, SetKeyMap and
SetSelection merely assign their argument to the proper member
variable. Notice that none of these operations delete the old
value---they assume the programmer will delete the old value if
necessary before resetting it.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \subsection{Defining Appearance}
    \label{defining appearance}

\begin{figure}
\begin{code}{0em}
Interactor* Punidraw::Interior () {
  return new VBox(
    new HBox(
      Commands(),
      new HGlue,
    ),
    new HBorder,
    new HBox(
      _viewer,
      new VBorder,
      new VBox(
        Tools(),
        new VGlue,
        new HBorder,
        new Panner(_viewer)
      )
    )
  );
}
\end{code}
\caption{Interior function definition}
\label{Interior function}
\end{figure}

Punidraw's Interior function (Figure~\ref{Interior function}) builds
the interactor composition that defines punidraw's look and feel.
Interior calls the Commands and Tools helper functions to build its
pull-down menus and tool palette.  The root of the composition is a
VBox. At the top will be the command menus (right-justified with some
HGlue).  Then a horizontal border separates the menus from the HBox
composition containing the viewer and the tool panel. The tool panel
itself is a VBox composition containing the tools and the panner that
pans the viewer.  The Interior function returns the overall
composition.  The Punidraw editor constructor calls Interior and
inserts this composition into itself.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        \subsubsection{Command Menus}

\begin{figure}
\begin{code}{0em}
Interactor* Punidraw::Commands () {
  MenuBar* commands = new MenuBar;

  commands->Include(FileMenu());
  commands->Include(EditMenu());

  return commands;
}
\end{code}
\caption{Commands function definition}
\label{Commands function}
\end{figure}

\begin{figure}
\begin{code}{0em}
PulldownMenu* Punidraw::FileMenu () {
  PulldownMenu* pdm = new PulldownMenu("File");

  Include(
    new NewCompCmd(
      new ControlInfo(
        "New", KLBL_NEWCOMP, CODE_NEWCOMP
      ),
      new GraphicComps
    ),
    pdm
  );
  Include(
    new ViewCompCmd(
      new ControlInfo(
        "Open...", KLBL_VIEWCOMP, CODE_VIEWCOMP
      )
    ), pdm
  );
  Include(
    new SaveCompCmd(
      new ControlInfo(
        "Save", KLBL_SAVECOMP, CODE_SAVECOMP
      )
    ),
    pdm
  );
  Include(
    new PrintCmd(
      new ControlInfo(
        "Print...", KLBL_PRINT, CODE_PRINT
      )
    ), pdm
  );
  Include(
    new QuitCmd(
      new ControlInfo(
        "Quit", KLBL_QUIT, CODE_QUIT
      )
    ), pdm
  );

  return pdm;
}
\end{code}
\caption{FileMenu function definition}
\label{FileMenu function}
\end{figure}

Figure~\ref{Commands function} shows the definition of the Commands
function, which simply creates a MenuBar instance, includes the
pull-down menus returned by the FileMenu (shown in
Figure~\ref{FileMenu function}) and EditMenu (Figure~\ref{EditMenu
function}) helper functions, and finally returns the menu bar.

The FileMenu routine produces a pull-down menu that implements the
File menu. FileMenu uses the Include helper function that takes
Command and PulldownMenu instances and effectively puts the command
into the menu.  The Include function actually puts the command into a
command control and then puts the command control into the menu.  Both
this Include function and its overloaded counterpart are detailed in
Section~\ref{Include functions}.

FileMenu creates an instance of the appropriate predefined command
subclass for each command in the menu: {\bf NewCompCmd} implements the
``New'' menu entry, {\bf ViewCompCmd} implements ``Open,'' {\bf
SaveCompCmd} implements ``Save,'' {\bf PrintCmd} implements ``Print,''
and {\bf QuitCmd} implements ``Quit.''  Each command constructor takes
at least a ControlInfo instance, which specifies its appearance to the
CommandControl that invokes it.  NewCompCmd also takes a Component
instance. When invoked, NewCompCmd will copy this instance and replace
the Punidraw object's component with the copy via
Punidraw::SetComponent.

Each ControlInfo is constructed with a string (called the
ControlInfo's {\bf label}) that identifies the command in the menu, a
string (called the {\bf keylabel}) that identifies the keyboard
equivalent, and a string (called the {\bf keycode}) that defines the
sequence of characters that activates the command from the keyboard.
Normally the keycode contains two characters: a normal ASCII or
control character and a null.  FileMenu uses keylabels and keycodes
that Unidraw predefines for its command and tool subclasses.

\begin{figure}[t]
\begin{code}{0em}
PulldownMenu* Punidraw::EditMenu () {
  PulldownMenu* pdm = new PulldownMenu("Edit");

  Include(
    new UndoCmd(
      new ControlInfo(
        "Undo", KLBL_UNDO, CODE_UNDO
      )
    ), pdm
  );
  Include(
    new RedoCmd(
      new ControlInfo(
        "Redo", KLBL_REDO, CODE_REDO
      )
    ), pdm
  );
  Include(
    new DeleteCmd(
      new ControlInfo(
        "Delete", KLBL_DEL, CODE_DEL
      )
    ), pdm
  );
  Include(
    new DupCmd(
      new ControlInfo(
        "Duplicate", KLBL_DUP, CODE_DUP
      )
    ), pdm
  );

  return pdm;
}
\end{code}
\caption{EditMenu function definition}
\label{EditMenu function}
\end{figure}

EditMenu is the helper routine for building the Edit menu.  It creates
{\bf UndoCmd}, {\bf RedoCmd}, {\bf DeleteCmd}, and {\bf DupCmd}
instances to implement the ``Undo,'' ``Redo,'' ``Delete,'' and
``Duplicate'' entries in that menu.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        \subsubsection{Tool Palette}

\begin{figure}
\begin{code}{0em}
Interactor* Punidraw::Tools () {
  VBox* tools = new VBox;

  Include(
    new SelectTool(
      new ControlInfo(
        "Select", KLBL_SELECT, CODE_SELECT
      )
    ),
    tools
  );
  Include(
    new MoveTool(
      new ControlInfo(
        "Move", KLBL_MOVE, CODE_MOVE
      )
    ),
    tools
  );
  Include(
    new ScaleTool(
      new ControlInfo(
        "Scale", KLBL_SCALE, CODE_SCALE
      )
    ),
    tools
  );
  Include(
    new RotateTool(
      new ControlInfo(
        "Rotate", KLBL_ROTATE, CODE_ROTATE
      )
    ),
    tools
  );
\end{code}
\caption{Tools function definition (first half)}
\label{Tools function (first half)}
\end{figure}

\begin{figure}
\small
\begin{code}{0em}
  const Coord unit = round(0.5*cm);

  Line* line = new Line(
    0, 0, unit, unit, stdgraphic
  );
  LineComp* lineComp = new LineComp(line);
  Include(
    new GraphicCompTool(
      new ControlInfo(
        lineComp, KLBL_LINE, CODE_LINE
      ), lineComp
    ), tools
  );

  SF_Rect* rect = new SF_Rect(
    0, 0, unit*2, unit, stdgraphic
  );
  rect->SetPattern(psnonepat);
  RectComp* rectComp = new RectComp(rect);
  Include(
    new GraphicCompTool(
      new ControlInfo(
        rectComp, KLBL_RECT, CODE_RECT
      ), rectComp
    ), tools
  );

  SF_Ellipse* ellipse = new SF_Ellipse(
    0, 0, unit, unit/2, stdgraphic
  );
  ellipse->SetPattern(psnonepat);
  EllipseComp* ellipseComp =
    new EllipseComp(ellipse);
  Include(
    new GraphicCompTool(
      new ControlInfo(
        ellipseComp, KLBL_ELLIPSE, CODE_ELLIPSE
      ), ellipseComp
    ), tools
  );

  return tools;
}
\end{code}
\caption{Tools function definition (second half)}
\label{Tools function (second half)}
\end{figure}

The Tools function (shown in Figures~\ref{Tools function (first half)})
and \ref{Tools function (second half)}) composes the controls in the
tools palette.  It uses the Include helper function that takes Tool
and Box instances and effectively puts the tool into the box, though
in reality it puts the tool into a panel control that it puts in turn
into the box (Section~\ref{Include functions} gives the details).

The first half of this function (Figure~\ref{Tools function (first
half)} composes the tools that manipulate existing graphical objects,
that is, the Select, Move, Scale, and Rotate tools.  As with the menu
commands, each tool is created with a ControlInfo instance that
specifies its appearance to the PanelControl instance that engages it.
PanelControls can be engaged via a keyboard equivalent as well as by
mouse clicking---thus the keylabel and keycode.

The second half of Include (Figure~\ref{Tools function (second half)})
composes the tools that instantiate new graphical components,
including line, rectangle, and ellipse components.  The tool objects
we'll use are all instances of GraphicCompTool, a general tool for
instantiating graphical components.  The GraphicCompTool constructor
takes a prototypical component; the tool will paste a copy (or a {\bf
clone}) of this component into the drawing whenever it is used.  The
clone is not an {\em exact} copy of the prototype, as the clone's
geometry (i.e., the location of its endpoints) depends on where the
user clicks with this tool engaged.

We must create the prototypical component before we construct the
corresponding GraphicCompTool. For example, the tool for instantiating
line components requires an instance of a {\bf LineComp}.  In turn,
the LineComp requires an instance of a {\bf Line} structured graphics
object~\cite{interviews:man,interviews:graphic} to define its
appearance, both in terms of geometry and graphics state attributes
(e.g., foreground and background colors, pattern, etc.).  Now, the
prototype's geometry is not important in this case because it has no
impact on the clone geometries.  However, each clone {\em will}
inherit a copy of the prototype's graphics state.\footnote{This is
true for the predefined components in the Unidraw library.  In
general, the GraphicCompTool's cloning semantics are defined by the
{\em prototype}, not the GraphicCompTool itself.  In Unidraw
terminology, the tool {\bf delegates} the definition of manipulation
semantics to the prototype component.  See
Tool(3U)~\cite{interviews:man} for more details.} We therefore create
the line object with arbitrary geometric information, but we specify a
complete set of graphics attributes by passing {\bf stdgraphic} in the
constructor.\footnote{When a graphic constructor is passed a graphic
in its trailing parameter, the new graphic will adopt the parameter's
graphics state.} The stdgraphic object is a Unidraw-initialized global
graphic object that is preset to a standard set of graphics
attributes, for example, black foreground color, white background
color, solid fill pattern, etc.

Once the line graphic object exists, we can instantiate the line
component instance.  Note that the line component is also passed to
the ControlInfo constructor and thus serves double-duty: whereas the
controls constructed thus far appear in the interface with textual
labels, the controls for engaging the GraphicCompTools have icons that
indicate the kind of graphic they create.  The ControlInfo constructor
can take an arbitrary graphical component instead of a string to
specify an iconic appearance.  Finally, we include the tool in the
palette as we have done before.

We use this procedure to create GraphicCompTools for instantiating
rectangles and ellipses, but with a difference.  Punidraw should
support only stroked (i.e., non-filled) rectangles and ellipses, but
the prototypes inherit a filled background pattern from stdgraphic.
Therefore we must set the {\bf SF\_Rect} (i.e., stroked-filled
rectangle) and {\bf SF\_Ellipse} (stroked-filled ellipse) graphic
objects' patterns explicitly to the {\bf psnonepat}, a global fill
pattern object that Unidraw predefines.  Graphical components
interpret psnonepat as specifying no fill pattern.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        \subsubsection{Include Functions}
        \label{Include functions}

\begin{figure}
\begin{code}{0em}
void Punidraw::Include (
  Command* cmd, PulldownMenu* pdm
) {
  ControlInfo* ctrlInfo = cmd->GetControlInfo();
  UControl* ctrl = new CommandControl(ctrlInfo);

  _keymap->Register(ctrl);
  pdm->Include(ctrl);
  cmd->SetEditor(this);
}

void Punidraw::Include (Tool* tool, Box* box) {
  ControlInfo* ctrlInfo = tool->GetControlInfo();
  UControl* ctrl = new VPanelControl(
    ctrlInfo, _curCtrl
  );

  _keymap->Register(ctrl);
  box->Insert(ctrl);
}
\end{code}
\caption{Include function implementations}
\label{Include function implementations}
\end{figure}

Figure~\ref{Include function implementations} reveals how the Include
functions are implemented.  Whether for commands or tools, the basic
idea is the same:
\begin{enumerate}

\item Get the ControlInfo from the command or tool object.

\item Create the appropriate UControl subclass (CommandControl for
commands, PanelControl for tools) with the ControlInfo as an argument
to define the appearance.

\item Register the control with the editor's keymap to enable keyboard
equivalents. 

\item Incorporate the control into the interface.  In the command case
this involves including the CommandControl in the pull-down menu;
PanelControls are inserted into the box that forms the panel.

\end{enumerate}

The Include function for commands must perform one extra operation: it
must tell the command which editor (i.e., {\em this}) to affect---the
command has no way of knowing itself.  Tools needn't be supplied this
information because the objects they affect are implied by their
direct manipulation.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \subsection{Viewer Initialization}

\begin{figure}
\begin{code}{0em}
void Punidraw::InitViewer () {
  const float w = 8.5 * inches;
  const float h = 11 * inches;

  GraphicView* view =
    (GraphicView*) _comp->Create(COMPONENT_VIEW);
  _comp->Attach(view);
  view->Update();

  _viewer = new Viewer(
    this, view, new Page(w, h), 
    nil, round(w/2), round(h/2)
  );
}
\end{code}
\caption{InitViewer function definition}
\label{InitViewer function}
\end{figure}

The last routine to discuss is InitViewer, shown in
Figure~\ref{InitViewer function}.  This routine creates a Viewer
instance and assigns it to Punidraw's \_viewer member.  The Viewer
constructor requires three parameters:
\begin{enumerate}

\item The  editor instance in which the viewer logically ``lives.''
The editor defines the graphical component being edited, and the
viewer will display a view of the editor's component.

\item The graphical component view (GraphicView instance) itself.

\item A {\bf Page} object, which delineates the drawing's boundaries.

\end{enumerate}
We'll also supply values for three optional constructor parameters.  A
{\bf Grid} object defines and displays a grid of points in the viewer,
and its presence constrains the operation of some tools and commands
so that they snap to the grid points. Punidraw will not have this
functionality, so we pass nil.  The last two parameters specify the
viewer's natural size.  Omitting these values is equivalent to
specifying zero natural size.  Viewers are infinitely shrinkable and
stretchable by default.

InitViewer's sole non-trivial task is to construct the appropriate
view of the component Punidraw edits and pass this view to the viewer.
The first step is to create the view instance.  We know that Punidraw
edits some sort of GraphicComp, but we don't necessarily know the
precise subclass, since it is passed in only as a GraphicComp.
Without knowing the component subject's class, we cannot directly
instantiate the proper component view class.

Instead, we use the Component class' Create operation.
Component::Create takes a {\bf view category} as an argument and
returns an instance of the component view subclass that's appropriate
for the component.  Unidraw predefines two component view categories:
{\bf COMPONENT\_VIEW} for generating GraphicView subclasses, and {\bf
POSTSCRIPT\_VIEW} for generating PostScriptView subclasses. Viewers
display GraphicView objects, so InitViewer specifies the
COMPONENT\_VIEW category.  Once the view instance is created,
InitViewer attaches it to the component and calls Update on the view
to conform its own state to the subject's.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Conclusion}

We've covered Punidraw's implementation in its entirety.  Punidraw as
it stands is functional and robust enough to generate real drawings,
but it is quite limited.  We could easily expand its capabilities by
incorporating more of the predefined components, commands, and tools
from the Unidraw library.  We could also derive from the predefined
objects or even create entirely new objects to add specialized
features.  Unidraw also defines a host of programming abstractions
that we haven't described to help you implement sophisticated
functionality.  These topics are addressed in subsequent tutorials in
this series.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\bibliographystyle{plain}
\bibliography{Bib/abbrev,Bib/local}

\end{document}
