# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Tim Budd on Wed Mar 24 10:18:05 1993 # # This archive contains: # cprog.sty gui.tex # LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH echo x - cprog.sty cat >cprog.sty <<'@EOF' % cprog.tex (or cprog.sty) - formatting of C programs % By \'Eamonn McManus . This file is not copyrighted. % $Header: cprog.tex,v 1.2.1.1 90/04/02 04:22:59 emcmanus Exp $ % This allows C programs to be formatted directly by TeX. It can be % invoked by \cprogfile{filename} or (in LaTeX) \begin{cprog} ... % \end{cprog} or (in plain TeX) \cprog ... \end{cprog}. In LaTeX, the % alternative form \begin{cprog*} is allowed, where spaces in C strings % are printed using the `square u' character (like LaTeX {verbatim*}). % In plain TeX, you have to use \csname cprog*\endcsname for this (sorry). % If you are using \cprogfile, say \cprogttspacetrue beforehand if you % want this effect. % The formatting is (necessarily) simple. C text is set in a normal Roman % font, comments in a slanted font, and strings in a typewriter font, with % spaces made visible as the `square u' symbol. Tabs are expanded to four % spaces (this does not look good when comments are aligned to the right of % program text). Some pairs of input characters appear as single output % characters: << <= >> >= != -> are respectively TeX's \ll \le \gg \ge \ne % \rightarrow. % The fonts below can be changed to alter the setting of the various parts % of the program. The \cprogbaselineskip parameter can be altered to % change the line spacing. LaTeX's \baselinestretch is taken into account % too. The indentation applied to the whole program is \cprogindent, % initially 0. Before and after the program there are skips of % \beforecprogskip and \aftercprogskip; the default values are \parskip % and 0 respectively (since there will often be a \parskip after the % program anyway). % This package works by making a large number of characters active. Since % even spaces are active, it is possible to examine the next character in % a macro by making it a parameter, rather than using \futurelet as one % would normally do. This is more convenient, but the coding does mean % that if the next character itself wants to examine a character it may % look at a token from the macro rather than the input text. I think that % all cases that occur in practice have been looked after. % The macros were thrown together rather quickly, and could do with some % work. For example, the big macro defined with [] taking the place of % {} could be recoded to use {} and so be more legible. The grouping of % two-character pairs should be controllable, since not everyone will want % it. The internal macros etc should have @ in their names, and should be % checked against LaTeX macros for clashes. % Allow multiple inclusion to go faster. \ifx\undefined\cprogsetup % The whole file. % Define the fonts used for program text, comments, and strings. % Note that if \it is used for \ccommentfont, something will need to % be done about $ signs, which come out as pounds sterling. \let\ctextfont=\sf \let\ccommentfont=\sl \let\cstringfont=\tt % Parameters. Unfortunately \newdimen is \outer (\outerness is a mistake) % so we need a subterfuge in case we are skipping the file. \csname newdimen\endcsname\cprogbaselineskip \cprogbaselineskip=\baselineskip \csname newdimen\endcsname\cprogindent \cprogindent=0pt \csname newdimen\endcsname\cprogwidth % Gets default=\hsize when cprog invoked. \csname newskip\endcsname\beforecprogskip \beforecprogskip=\parskip \csname newskip\endcsname\aftercprogskip \aftercprogskip=0pt \csname newif\endcsname\ifcprogttspace \csname newif\endcsname\ifpascal \csname newif\endcsname\ifmodula % Same as Pascal but no {comments}. \csname newif\endcsname\ifsmalltalk % Same as Pascal but "comments". {\def\junk{\fi\fi\fi}} % If skipping. \let\cprogesc\relax \def\cprogescape#1{\makeactive#1\cprogescont} \def\cprogescont#1{% \def\cprogesc{% \makeactive#1\def#1{% \begingroup \catcode`\\0 \catcode`{1 \catcode`}2 \catcode`\%14 \catcode` 10 \clinegroup{}}}} \def\makeactive#1{\catcode`#1=\active} \def\makeother#1{\catcode`#1=12} {\obeyspaces\gdef\activespace{ } \obeylines\gdef\activecr{^^M}} {\catcode`|=\catcode`\\ \makeactive\\ |gdef|activebackslash{\}} {\catcode9=\active \gdef\activetab{^^I}} % Following is supposed to be in plain.tex or lplain.tex, but early % versions omitted the \global. {\makeactive_ \global\let_\_} % The following group makes many characters active, so that their catcodes % in the \cprogchars macro are active, allowing them to be defined. We % could alternatively define more stuff like \activebackslash and use % \expandafter or (carefully) \edef to expand these in the macro. \begingroup \catcode`[=\catcode`{ \catcode`]=\catcode`} \makeactive! \makeactive" \makeactive' \makeactive( \makeactive* \makeactive- \makeactive/ \makeactive< \makeactive> \makeactive? \makeactive^ \makeactive_ \makeactive\{ \makeactive| \makeactive\} \gdef\activestar[*] \gdef\cprogchars[% \makeother##\makeother$\makeother&\makeother\%\makeother^% \makeactive"\makeactive'\makeactive*\makeactive-% \makeactive<\makeactive>\makeactive?\makeactive{\makeactive|\makeactive}% \makeactive!\makeactive\\\makeactive_\expandafter\makeactive\activetab% \def!##1[\string!\null##1]% \def?[\string?\null]% Avoid ?` ligature. \def-##1[\ifx>##1$\rightarrow$\else$\string-$##1\fi]% \def"[\cquote"[\tt\string"]]\def'[\cquote'[\tt\ttquote]]\def*[$\string*$]% % We use \aftergroup in < and > to deal with the fact that #1 might % itself examine the following character. \def<##1[[\ifx-##1$\leftarrow$\else$\ifx<##1\ll$ \else \string<$\aftergroup##1\fi\fi]]% \def>##1[[$\ifx>##1\gg$\else \string>$\aftergroup##1\fi]]% \ifmodula \pascaltrue \fi % Except that {...} is used for sets. \ifsmalltalk \def{[\begingroup \dulllbrace\scommentsetup\def}[\/\endgroup ]]% \makeactive^\def^[$\uparrow$]% \else \ifpascal \ifmodula \dulllbrace \else \def{[\begingroup \dulllbrace{\ccommentsetup\def}[\/\endgroup }]]% \fi \makeactive(\let(=\pascalcomment \makeactive^\def^[$\uparrow$]% \else \dulllbrace\makeactive/\let/=\ccomment \fi\fi \def}[$\}$]\def|[$\string|$]\def~[$\sim$]\let_\_% \expandafter\def\activebackslash[$\backslash$]% \obeyspaces \expandafter\def\activespace[\leavevmode\space]% \expandafter\def\activetab[\ \ \ \ ]% \obeylines \expandafter\def\activecr[\strut\par]] \gdef\cprogarg[\expandafter\def\activebackslash##1[\ifx##1e\let\next\cprogend \else$\backslash$\let\next##1\fi\next]\eatcr] \gdef\cprogend nd#1{cprog#2}[\endcprogarg] % #1 can be space, #2 *. \gdef\dulllbrace[\def{[$\{$]] \endgroup \chardef\ttquote=13 % Undirected single quote. \begingroup \makeactive" \makeactive' \makeactive! \gdef\cquote#1#2{% #1 is the quote, " or ', #2 how to set it. \begingroup #2\ifsmalltalk\ccommentfont\else\cstringfont\fi \makeactive\\% \ifpascal \makeother\\\makeother^% \else \expandafter\let\activebackslash\quotebackslash \fi \expandafter\edef\activespace{\ifcprogttspace\char`\ \else\ \fi}% \expandafter\let\activecr=\unclosedstring \def!{\string!\null}% No !` ligature. \makeother*\makeother-\makeother/\makeother<\makeother>% \makeother_\makeother\{\makeother\}\makeother|\makeother~% \ifx"#1\let'\ttquote \else \makeother"\fi \def#1{#2\endgroup}} \endgroup \csname newhelp\endcsname\cprogunclosedstr{% A string or character constant earlier in the line was unclosed.^^JSo I'm closing it now.} \def\unclosedstring{% \escapechar-1% \errhelp\cprogunclosedstr \errmessage{Unclosed string}% \endgroup} \newlinechar=`^^J \def\quotebackslash#1{\char`\\% \expandafter\ifx\activecr#1\strut\par \else\if'\noexpand#1\ttquote\else\string#1\fi\fi} % In a comment, we shrink the width of the opening / to that of a space so % that the stars in multiline comments will line up. We also shrink the % closing * for symmetry, but not in Pascal where it looks nasty. % Note that \end{cprog} is not recognised in strings or comments. \def\spacebox#1{\leavevmode \hbox to \spaceskip{#1\hss}} \begingroup \makeactive* \makeactive! \makeother/ \gdef\ccommentsetup{\ccommentfont \makeother-\makeother'\makeother"\makeother/% \def!{\string!\null}\expandafter\def\activebackslash{$\backslash$}} % smalltalk ``comments'' are actually bold \gdef\scommentsetup{\bf \makeother-\makeother'\makeother"\makeother/% \def!{\string!\null}\expandafter\def\activebackslash{$\backslash$}} \gdef\ccomment#1{% \let\next\relax \ifx#1*\bgroup \ccommentsetup \spacebox{\ctextfont\string/}*% \makeactive*\def*{\commentstar/}% \else\if\noexpand#1/\begingroup //\ccommentsetup \clinegroup\activecr \else \string/\let\next#1% \fi\fi\next} \gdef\pascalcomment#1{% \ifx#1*\bgroup \ccommentsetup \let\next\dulllbrace \makeother(% \spacebox{\ctextfont\string(}*\makeactive*\def*{\commentstar)}% \else (\let\next#1\fi \next} \obeylines \long\gdef\clinegroup#1#2^^M{#2\endgroup#1}% \endgroup \def\commentstar#1#2{% {\if#1\noexpand#2\egroup \ifpascal\else\aftergroup\spacebox\fi\fi}{$*$}#2} % We usually have an active ^^M after \cprog or \begin{cprog}. \def\eatcr#1{{\expandafter\ifx\activecr#1\else\aftergroup#1\fi}} % Expand to stretch and shrink (plus and minus) of parameter #1. \def\stretchshrink#1{\expandafter\eatdimenpart\the#1 \end} \def\eatdimenpart#1 #2\end{#2} \ifx\undefined\baselinestretch \def\baselinestretch{1}\fi \def\cprogsetup{\ctextfont \cprogchars \parskip=0pt\stretchshrink\parskip \ifdim \cprogwidth=0pt \else \hsize\cprogwidth \fi \cprogesc \spaceskip\fontdimen2\font \xspaceskip\spaceskip \baselineskip=\baselinestretch\cprogbaselineskip \parindent=\cprogindent \vskip\beforecprogskip} \def\endcprog{\endgroup \vskip\aftercprogskip} \def\cprogfile#1{\begingroup \cprogsetup \input#1\endcprog} \def\cprog{\begingroup \cprogttspacefalse \cprogsetup \cprogarg} % Like {verbatim*}, {cprog*} uses `square u' for spaces in quoted strings. \expandafter\def\csname cprog*\endcsname{% \begingroup \cprogttspacetrue \cprogsetup \cprogarg} \expandafter\let\csname endcprog*\endcsname=\endcprog % In LaTeX we need to call \end{cprog} properly to close the environment, % whereas in plain TeX this will end the job. The test for LaTeX is not % bulletproof, but most plain TeX documents don't refer to the LaTeX logo. \ifx\undefined\LaTeX \let\endcprogarg=\endcprog \else \def\endcprogarg{\ifcprogttspace\end{cprog*}\else\end{cprog}\fi} \fi \fi % \ifx\undefined\cprogsetup \endinput @EOF chmod 644 cprog.sty echo x - gui.tex cat >gui.tex <<'@EOF' \documentstyle[cprog]{article} \begin{document} \title{Graphical User Interfaces} \author{Tim budd} \maketitle \begin{abstract} This is a rough-draft for a proposed new chapter to be included in the second edition of my book ``An Introduction to Object Oriented Programming'', published by Addison-Wesley, 1991. It will probably appear between the current chapters 15 and 16. Constructive comments and criticism will be gratefully appreciated. (No date has been set for the second edition). \end{abstract} \section{Introduction} Graphical User Interfaces have been popularized in recent years by systems such as the Macintosh, Windows 3.0, OS/2 Presentation Manager, Motif, Open Look, InterViews, and others. GUI's tend to be more flexible and intuitive than older character-based interfaces, and are thus easier to use. This is particularly true for novice computer users. Ironically however, developing applications that are easy for novice users to understand is a difficult and challanging task for the programmer. In this chapter we will explore some of the ways that object-oriented techniques can be used to simplify this task. In large part graphical user interfaces have grown up hand-in-hand with object-oriented programming. The Smalltalk-80 system was made popular as much for its innovative interface as for its innovative language features. The fact that object-oriented techniques were used in the creation of this interface did much to popularize the idea of object-oriented programming in the mind of the computing public. The Smalltalk system also brought with it a new way of structuring programs; a technique called event driven programming. \section{Event Driven Execution} The first conceptual hurdle a programmer must overcome in attempting to understand the techniques used in developing graphical user interfaces is the idea of structuring programs around event-driven execution. A conventional program proceeds on its own agenda. We can think of execution as being something like a finger that is moving through the program from beginning to end. At various points the program may interact with the user, but the nature of the responses the program is willing to deal with is very proscribed. For example a program may ask questions of the user, and respond only to simple yes/no answers typed at a keyboard. In an event driven program, on the other hand, the user is in control. The program largely {\em reacts} to the user, rather than being {\em proactive}. In an event driven program execution is confined largely to a single loop. Figure~\ref{event} describes in pseudo-code the main program for almost all event-driven applications. The initialization and cleaning up stages start and terminate the application. Between these two extremes the program simply loops waiting for the user to do something, such as moving the mouse, hitting the keyboard, or inserting a disk into a floppy disk drive. When the user makes an action, the application reacts, then goes back to waiting for the next action. \begin{figure} \pascaltrue\begin{cprog} program main; begin initialize application; while not finished do begin if user has done something interesting respond to it end; clean up application; end. \end{cprog}\pascalfalse \caption{The event driven style of programming}\label{event} \end{figure} The ``interesting things'' the user can do are called {\em events}. Since the flow of control is directed by the sequence of events, this is called event-driven execution. Not all events need to correspond to user initiated activities. Activities such as inserting a disk can cause a sequence of internally generated events, and the program will respond to these in the same way as to user generated events. Object-oriented programming fits naturally with event-driven execution because the flow of control is so highly structured. It is relatively easy to create a library of classes which go through the motions of an event driven application, but perform no actual work. By subclassing from this library and changing the meaning of just a few methods, we can add the ``work'' part of an application to this library without needing to rewrite the ``control'' portions. This is exactly what is done by the systems we will describe in the remainder of this chapter. Steve Burbeck of Apple~\cite{macapp} has described a typical event-driven application built using a system such as the ones we will subsequently describe as being constructed using an ``upside down library''. In a traditional program a software library may provide bits and pieces of code, but it is the job of the programmer to write the ``glue'' that holds everything together. Using a GUI system the library provides the ``glue'', and the programmer merely specializes pieces of the library, using subclassing and overriding, to obtain application specific behavior. Because such systems define the fundamental structure of a program, they are sometimes referred to as {\em application frameworks}. The primary means by which an application framework is customized to create a new program is through the use of inheritance. The application framework provides one or more abstract superclasses; classes that will be overridden by the programmer. For the purposes of explaining the mechanism used for customization, we can divide the methods defined in these classes into three categories: \begin{enumerate} \item Base methods. These provide certain essential functionality which is useful to the customization process, but will probably not be overridden by the programmer. An example might be a method which returns the coordinates of the cursor when a mouse-press occurred. \item Template, or algorithm methods. These describe an abstract algorithm, for which the specific details are left to other methods. An example might be a method which implements the event loop of Figure~\ref{event}. These methods provide the structure for the application framework, without doing any of the actual work. As with base methods, template methods are not usually overridden in a new application. \item Abstract methods. These methods do the actual work of the application. In the application framework an abstract method is often simply a dummy procedure which performs nothing. By overriding the abstract methods, actions specific to a new application are provided. \end{enumerate} For example, in the MacApp system we will describe later, a template method {\sf ReadFromFile} is used to read information from a file. This method is defined in terms of several other methods, such as a base method which asks the user for the name of the file to open, a method which opens the given file, and an abstract method {\sf DoRead} which reads the contents of the file. To specialize this process it is only necessary to change the meaning of the latter method. Thus when building a new program using an application framework the programmer simply creates several new classes as subclasses of those provided by the application framework, overriding abstract methods to create application-specific behavior. The application framework plays the role of both the main program (the ``top'' part of an application) and often provides certain base functional (the ``bottom'' part of an application), leaving it to the programmer to fill in the details in the middle. \section{The Smalltalk Model-View-Controller Triad} The ancestor of all application frameworks is found in the language Smalltalk-80. The Smalltalk graphical windowing system is based upon the concept of dividing an application into three categories, called the {\em model}, the {\em view}, and the {\em controller\/} (Figure~\ref{mvc}). Each portion of the application has a specific task, and to accomplish that task each portion must interact with the other two. \setlength{\unitlength}{3mm} \begin{figure} \begin{picture}(40,30)(0,0) \put(0,9){\shortstack{User \\ Input}} \put(3,10){\vector(1,0){3}} \put(10,10){\circle{8}} \put(10,10){\framebox(0,0){\scriptsize Controller}} \put(30,10){\circle{8}} \put(30,10){\framebox(0,0){\scriptsize View}} \put(20,20){\circle{8}} \put(20,20){\framebox(0,0){\scriptsize Model}} \put(33,10){\vector(1,0){3}} \put(38,9){\shortstack{Visual \\ Output}} \put(14,9.5){\vector(1,0){12}} \put(26,10.5){\vector(-1,0){12}} \put(12,12){\vector(1,1){5}} \put(28,12){\vector(-1,1){5}} \end{picture} \caption{The Model-View-Controller Triad}\label{mvc} \end{figure} The model component of the MVC triad contains the data representing the internal state of an application. The model can be an instance of any Smalltalk class; although there is a class {\sf Model} that can be subclassed, it is not necessary to do so and many applications use other classes for models. For a text editor the model might be a string representing the text being manipulated; for a bar graph or pie chart it could be the data being displayed, and for a menu it might be a list of titles and associated actions. The distinguishing features of a prototypical model are that they perform some service or action, and that they know nothing of their visual appearance. Mediating interaction between the user and the model are views and controllers. The view is responsible for the visual representation of a model on an output device, such as a display terminal. There may be several views of one model; for example portions of a spreadsheet might be displayed in a bar graph form, or a pie chart form, or as a list of numbers. A view can also have nested subviews; for example when a complex window has several individual components. The most important message a view must repond to is the message {\sf display}, which requests the visual presentation for the model be generated or updated. Views may represent an entire model or only certain aspects of the model. A view must know about the model it is representing, but need not have any knowledge concerning other views. A system supplied class {\sf View} and associated subclasses provide a number of methods to assist in common activities such as drawing borders around windows, drawing title bars, and the like. A new view is almost always produced by subclassing an existing view class in the Smalltalk-80 library. Figure~\ref{viewmess} shows a few of the messages understood by instances of the standard views. \begin{figure} \begin{tabular}{l l} {\sf initialize} & set instance variables \\ {\sf model:} aModel & establish model for view \\ {\sf controller:} aController & establish controller for view \\ {\sf defaultController} & return a controller for this view \\ {\sf containsPoint:} aPoint & true if point is in view \\ {\sf borderWidth:} aValue & set border width \\ {\sf borderColor:} aColor & set border color \\ {\sf insideColor:} aColor & set inside color \\ {\sf clear} & erase view (including border) \\ {\sf clearInside} & erase inside of view \\ {\sf flash} & complement window twice in succession \\ {\sf display} & redraw view \\ \end{tabular} \caption{Messages understood by views}\label{viewmess} \end{figure} Conventionally each view class maintains the model in an instance variable of the same name, as well as a variable containing the controller. A model, on the other hand, does not usually contain any direct connection to a view. This matches the idea that a model can exist with several views, and that these views may be created and destroyed without altering the model. This can also promote reusability of code that implements the model. A controller class is used to guide user input. A system-wide controller traps user activity such as moving or depressing the mouse, or depressing a key at the keyboard. This system utility keeps track of all the controllers that have been created, and selects an appropriate controller for each activity, passing information to the controller in the form of a message. As with views, controllers are usually created as instances of classes which already exist in the Smalltalk-80 library. The creation of a new controller is almost always accomplished as part of the initialization process during the creation of a new view, and there is usually a one-to-one relationship between controllers and views. Standard system views, in fact, include a method ({\sf defaultController}, see Figure~\ref{viewmess}) which returns an instance of the appropriate type of controller for the view. Figure~\ref{controlmess} illustrates some of the methods defined in the standard control classes. Once a controller is given management of the system (after it has responded affirmatively to a {\sf isControlWanted} message), it is in charge of responding to all activity until it relinquishes its management responsibilities. \begin{figure} \begin{tabular}{l l} {\sf isControlWanted} & control inquiry \\ {\sf startUp} & initialize control cycle \\ {\sf controlInitialize} & initialize controller \\ {\sf controlLoop} & cycle through control activities \\ {\sf isControlActive} & control reinquiry \\ {\sf controlActivity} & do control process \\ {\sf yellowButtonActivity} & yellow button was pressed \\ {\sf redButtonActivity} & red button was pressed \\ {\sf blueButtonActivity} & blue button was pressed \\ {\sf controlTerminate} & close down controller \\ \end{tabular} \caption{Messages understood by controllers}\label{controlmess} \end{figure} The default behaviors defined for many of the methods shown in Figure~\ref{controlmess} simplify the creation of new controllers. For example the method associated with the message {\sf startUp} invokes the initialization and clean-up methods {\sf controlInitialize} and {\sf controlTerminate}, as well as starting the control loop. The control loop repeatedly asks whether control is still active ({\sf isControlActive}) and if so performs the {\sf controlActivity}. The default {\sf controlActivity} checks for key or button presses, and if so invokes a further method. Thus a simple application may need only modify the meaning of a few messages, such as the method {\sf yellowButtonActivity}. (The Smalltalk-80 classes display some of their historical traditions in not only assuming a three button mouse, but associating colors with each of the buttons). A trace of several senarios may help in understanding the interactions between the three portions of the MVC triangle. Suppose we have an application with two windows. Each window will automatically become ``active'' when the cursor associated with the mouse is over the portion of the display controlled by the window. Thus when the mouse moves and no other controller is managing the system, the supervising controller will ask each of the two controllers associated with the views if they want control. The controllers will use the default method, which responds true if the cursor is within the boundary of the view. The method {\sf isControlActive} will continue to return true as long as the mouse remains within the view. Moving the mouse outside of the window will cause {\sf isControlActive} to return false, and the controller will relinquish management back to the system. As part of the initialization (or activation) process for the controller the message {\sf display} will be sent to the view. Just as each view maintains a direct link to its controller via an instance variable, each controller also maintains a direct link back to its view. As part of the display process, a view may query the model to obtain its current settings. The information obtained from the model is then used to create a graphic display. Once the display is completed, action returns to the controller. Suppose now the user clicks the mouse in a manner intended to produce some change in the model. The {\sf controlActivity} method will decipher the mouse click, and turn it into a message specific to the button pressed, say {\sf YellowButtonActivity}. The user supplied subclass of {\sf Controller} may then turn this command into an application specific message either to the view or directly to the model itself. In this manner the model finally receives a message indicating a change should take place. For example the controller may have moved a line in a pie chart, which is translated into a message to the model to increase the percentage of some quantity. The model makes the appropriate modifications to its own internal state; and we reach a seemingly difficult quandary. How is the model to indicate to its associated views that they now need to update their displays? A fundamental principle of the MVC design is that models should be ignorant of the display. Yet surely the views must somehow be made aware of their need for modification. The solution in Smalltalk-80 is provided through a very general mechanism of {\em dependencies}. A system provided dictionary is maintained of objects and their {\em dependents}. When a new view is created it registers its model in this dictionary and associates itself as a dependent. A single object can have many dependents, such as when a model has several views. When a model makes a significant change, it sends a message to this dictionary indicating that it has been updated. The dictionary then transmits an {\sf update} message to each listed dependent. In this manner the dependents are alerted without any direct access from the model. To summerize, the MVC triad separates the creation of a graphical user interface into three smaller components. Each of these components has a specific task, and interacts with each of the other members of the triad in a structured fashion. By providing example or template classes from which the user can subclass, the Smalltalk-80 standard class library makes the creation of new user interfaces relatively easy. A very complete description of the MVC model can be found in Volume II of the book {\sf Inside Smalltalk}~\cite{pugh}. \section{The Interactor Model} One complaint that is sometimes heard about the MVC model concerns the separation of input handling from output handling. Input handing in the MVC triad is the responsibility of the controller, while output handing is the primary responsibility of the view. Yet these two tasks are often intimately tied together, a fact reflected in the strong ties that bind these two portions of the triangle together. The InterViews system~\cite{interviews} simplifies the design of user interfaces by being designed around a single abstraction, the interactor. An {\em interactor\/} occupies a rectangular region of an output device (such as a screen) and is responsible for managing the display in that area. The primary messages used to control the behavior of an interactor are {\sf Redraw}, which is used to redraw a portion of the display, and {\sf Handle}, which is used to catch input events. In practice the model portion of the interface remains, although its interaction is less structured than in the MVC triad. Thus we have replaced the Model-View-Controller triangle with an Interactor-Model pair. Just as the Smalltalk-80 library provided a number of different types of ready made classes for controllers and views, the Interviews system provides a wealth of interactors. Common interactors include scenes (textual or graphical displays), buttons, and boxes. The latter permit interactors to be stacked either horizontally or vertically. To illustrate, we will consider the Solitaire game studied in Chapter 10. The primary window is class {\sf GameWindow}, which is declared as a subclass of {\sf monoscene}. The interactor for the game window, however, shares the screen with two buttons. To create these, the two buttons are first placed next to each other in a horizontal box (or {\sf HBox}). This box is then stacked vertically under the game window, using a vertical box (or {\sf VBox}). The resulting application is then ``inserted'' into the variable {\sf world}, which is an instance of {\sf World}, the ultimate ``controlling'' class for InterViews (Figure~\ref{world}). Once all the interactors for an application have been established, the application is set in motion by sending the message {\sf run} to the world object. \begin{figure} \begin{cprog} int main (int argc, char ** argv) { World world("solitaire", argc, argv); game = new GameWindow; world.InsertApplication( new VBox(game, new HBox(new QuitButton, new StartButton))); world.Run(); } \end{cprog} \caption{Creating the main components of the solitaire application}\label{world} \end{figure} To assist in the layout of interactors on the display device surface, every interactor maintains a shape value (an instance of the InterViews class {\sf Shape}) in an instance variable. The shape of an interactor is not rigid; rather the shape value defines the optimum shape the interactor would desire, and instructions for how the shape can grow or shrink. These should be set in the constructor for the interactor, as part of the initialization process (Figure~\ref{constructor}). \begin{figure} \begin{cprog} GameWindow::GameWindow(){ // create a new shape for our drawing area shape = new Shape; shape->Rect(BoardWidth, BoardHeight); // create a new sensor so that we can catch mouse down events input = new Sensor; input->Catch(DownEvent); // create a new painter for drawing painter = new Painter; ... } \end{cprog} \caption{Creating a new game window}\label{constructor} \end{figure} Each interactor also maintains an instance variable named {\sf input}, which holds an instance of class {\sf Sensor}. A sensor describes the type of input events (mouse motions or keypresses) the interactor is willing to handle. Only requested events will be passed on to the interactor. Finally to produce a graphical output each interactor maintains a {\sf canvas}. The canvas for an interactor can be manipulated, for example for writing or drawing lines, using an instance of class {\sf Painter}. Most often this output takes place in response to a {\sf Redraw} message, which is given as arguments four coordinate values describing the portion of the window to be updated. The solitaire application chooses to ignore these arguments, and instead simply redraws the entire screen (Figure~\ref{redraw}). \begin{figure} \begin{cprog} void GameWindow::Redraw(Coord a, Coord b, Coord c, Coord d) { // first clear the entire playing area clearArea(0,0, BoardWidth, BoardHeight); // then display the card piles for (int i = 0; i < 13; i++) allPiles[i]->display(); } \end{cprog} \caption{The overridden method {\sf redraw} in the class {\sf GameWindow}}\label{redraw} \end{figure} The {\sf Handle} message is produced whenever an input event is generated for which an appropriate sensor exists. An argument is passed along with the handle message. This argument is an {\em event record}, and defines the appropriate characteristics of the event. For example, the event record for a mouse down event records the coordinates of the location where the cursor was located when the mouse was pressed. An application class specifies meaning for these activities by redefining the methods associated with this message. Many of the system provided interactors turn a {\sf Handle} into yet another message. For example, a {\sf Button} is an interactor which turns a mouse press action into a call on the method {\sf Press}. This method is then overridden to provide customized behavior for the button. In the Solitaire game described in Chapter 10 the {\sf GameWindow} class redefined the message {\sf Handle} so that it searches the piles of cards, discovering which pile (if any) was under the cursor at the time of a mouse click (Figure~\ref{handle}). If an appropriate pile is found the message {\sf select} is sent to the pile along with arguments representing the position of the mouse click. \begin{figure} \begin{cprog} void GameWindow::Handle (Event& e) { // we are only interested in mouse down events if (e.eventType != DownEvent) return; for (int i = 0; i < 13; i++) if (allPiles[i]->contains(e.x, e.y)) { allPiles[i]->select(e.x, e.y); return; } return; } \end{cprog} \caption{The overridden method {\sf Handle} in class {\sf GameWindow}}\label{handle} \end{figure} By combining input and output activies into one class, the InterViews class library simplifies the structure of graphical user interfaces. The interactor model, on the other hand, seems well suited for only relatively simple interfaces, and for applications in which the layout of the display remains relatively static during execution. In the next section we will examine a different approach to this problem. \section{The Application-Document-View Model} The Macintosh personal computer has arguably popularized the idea of a graphical user interface more than any other system. The Macintosh standard user interface, as described by Apple's {\em Human Interface Guidelines}, is flexible, intuitive, and relatively easy for novice users to understand. But this does not imply that it is easy to create new applications that fit the Macintosh ideal. In fact the Macintosh has a reputation for being an extremely difficult system to program. Among the many problems that Macintosh programmers must face are the fact that programs in the Macintosh world can be initiated in any one of three different ways, each requiring a different response; they must be ready to deal with outside applications, such as desk accessories or the scrapbook; they must be ready to handle windows being moved and resized during execution; and under the multifinder and latest version of the operating system they must be ready at any time to be suspended and restarted. All this is complex, and makes developing a robust Macintosh application an extremely difficult task. A number of software libraries, both object-oriented and conventional, have been created to help simplify the task of application development for the Macintosh. The central idea in all of these is to hide the details involved in dealing with window manipulation, desk accessories, menu manipulation, and the like and allow the programmer to concentrate on just the unique features of the application being created. Probaby the best known of such systems, and the one we will describe here, is the MacApp library of Object Pascal utilities~\cite{macapp}. The prototypical Macintosh application is slightly different than the applications we have discussed in the previous sections. A typical Macintosh application is based around the idea of {\em documents}. A document, like the model portion of the MVC triad, contains the essential information used to describe the current state of an application. An example document might be the current file contents in a text editor, or the current canvas in a drawing program. However unlike the MVC triad, where we assumed we had a single model and many different views, it is assumed in the Macintosh world that an application may be working with several documents at the same time, and can easily move between them. Thus a text editor can work with several files at once; similarly a user can be drawing in several paintings at the same time. \setlength{\unitlength}{3mm} \begin{figure} \begin{picture}(40,30)(0,0) \put(10,19){\shortstack{User \\ Input}} \put(13,20){\vector(1,0){3}} \put(10,10){\circle{8}} \put(10,10){\framebox(0,0){\scriptsize Document}} \put(30,10){\circle{8}} \put(30,10){\framebox(0,0){\scriptsize View}} \put(20,20){\circle{8}} \put(20,20){\framebox(0,0){\scriptsize Application}} \put(33,10){\vector(1,0){3}} \put(38,9){\shortstack{Visual \\ Output}} \put(14,9.5){\vector(1,0){12}} \put(26,10.5){\vector(-1,0){12}} \put(17,17){\vector(-1,-1){5}} \put(23,17){\vector(1,-1){5}} \end{picture} \caption{The Application-Document-View Triad}\label{adp} \end{figure} A program is divided into three components. These are the {\em application}, the {\em document}, and the {\em view} (Figure~\ref{adp}). The application is the controlling part of the system. There is always just a single instance of the application class created in any program, a subclass of the system provided class {\sf TApplication}.\footnote{The MacApp libraries uses an initial prefix to indicate the type of entity being named. Thus classes always begin with a ``T'', initialization methods with an ``I'', and constants with a ``k'', among others.} The application initializes the system, and waits for the user to create a new document or request to work on an existing document. In the MacApp classes a new document is created using the method {\sf DoMakeDocument}. The default methods in the MacApp library take care of managing the menu bar (including access to desk accessories and the scrap book), and handling of a few common methods, such as the ``quit'' method used to terminate the application. By overriding further methods the user can add new menu items and other commands. Figure~\ref{apmethods} shows the methods most commonly overridden by new applications. \begin{figure} \begin{tabular}{l l} {\sf IApplication} & initialize application \\ {\sf DoMakeDocument} & create a new document \\ \end{tabular} \caption{Messages understood by applications}\label{apmethods} \end{figure} A document, as we have noted already, contains the information describing the state of whatever objects the application is manipulating. A view provides the visual display of this information. A document must have at least one view, but can have more, just as a model could have multiple views in the MVC design. The document is created by subclassing the class {\sf TDocument}, and need only override the methods used to open, create and store documents, and methods used to respond to menu selections. Optional methods that can also be overridden control the undoing of actions and the printing of documents. Figure~\ref{docmethods} shows some of the more common methods overridden by application documents. \begin{figure} \begin{tabular}{l l} {\sf DoInitialState} & initialize document \\ {\sf DoRead} & read in a document from disk \\ {\sf DoNeedDiskSpace} & compute amount of disk to store document \\ {\sf DoWrite} & store document \\ {\sf DoMakeViews} & make views for document \\ {\sf DoMakeWindows} & make windows for document \\ {\sf Free} & release any storage for document \\ \end{tabular} \caption{Messages understood by documents}\label{docmethods} \end{figure} MacApp distinguishes between a {\em window}, which includes a title, close and zoom boxes, and so on, and a {\em view}, which is simply the information being displayed. (In actual fact the corresponding classes are related, but it is easier from the design point of view to think of them as separate.) The simplest type of application will just use a standard window, and concentrate on customizing a special purpose view. A new type of view is created by subclassing {\sf TView}, and must redefine the methods used to draw the screen and respond to key presses and mouse clicks. If printing is permitted in the application the view is also usually responsible for the actual printing task. Figure~\ref{macappviewmess} shows some of the more common messages understood by views. \begin{figure} \begin{tabular}{l l} {\sf Draw} & redisplay view \\ {\sf DoMouseCommand} & respond to mouse down \\ {\sf DoSetCursor} & alter cursor when over view \\ \end{tabular} \caption{Messages understood by MacApp views}\label{macappviewmess} \end{figure} A plethora of classes that we will not discuss also help simplify the tasks associated with handling menus, scroll bars, text editing, and other features commonly found in Macintosh applications. We will illustrate MacApp by describing how an interface could be constructed to the Billiards game of Chapter~16.\footnote{In actual fact we need to change the Chapter~16 code slightly, but this will be taken care of in the revision.} We start by defining a new application class, which we shall call {\sf TBilliardApplication}. Figure~\ref{TBilliardApplication} shows the declaration of this class, as well as the definition of the one method it creates, and the main program for the application. The main program is sterotypical for MacApp programs. It intializes the MacApp system, creates and initializes an application object, and starts the application running. The function {\sf FailNil} is a convenient function which will display an error message if the {\sf new} function was unable to create a dynamic object because of memory limitations. \begin{figure} \pascaltrue\begin{cprog} type TBilliardApplication = object(TApplication) function DoMakeDocument(itsCmdNumber:CmdNumber) : TDocument; end; procedure TBilliardApplication.DoMakeDocument (itsCmdNumber:CmdNumber):TDocument; var newDocument : TBilliardDocument; begin new(newDocument); FailNil(newDocment); { initialize it - arguments refer to resources } newDocument.IDocument('bill', 'bill', false, false, false, false); DoMakeDocument := newDocument; end; begin { main program } InitUMacApp(5); { number of handles} new(theApplication); { create the application } FailNil(theApplication); { make sure it worked } theApplication.IApplication('bill'); { initialize it} theApplication.Run; end. \end{cprog}\pascalfalse \caption{The class {\sf TBilliardApplication}}\label{TBilliardApplication} \end{figure} The method {\sf DoMakeDocument} is provided with a number used to identify the document internally. After creating the document (again using {\sf FailNil} to insure the creation was sucessful), the document is initialized. The arguments to the initialization method {\sf IDocument} refer to the use of resources, and are not important for our discussion here. The document created in Figure~\ref{TBilliardApplication} is an instance of {\sf TBilliardDocument}, shown in Figure~\ref{TBilliardDocument}. The document will maintain information about the state of the model in three variables, one for a window, one for the view contained in the window, and the actual data for the application maintained as an instance of the class {\sf billiardUniverse} from Chapter 16. Three methods are overridden. The first is used to initialize the document, while the second and third create the view and window, respectively. The window is an instance of the class {\sf TWindow} and is created by the function {\sf NewSimpleWindow}. The arguments to the latter are again unimportant for our discussion here. \begin{figure} \pascaltrue\begin{cprog} type TBilliardDocument = object(TDocument) theView : TBilliardView; theWindow : TWindow; theModel : billiardUniverse; procedure DoInitialState; override; procedure DoMakeViews (forPrinting : Boolean); override; procedure DoMakeWindows; override; end; procedure TBilliardDocument.DoInitialState; begin new(theModel); FailNil(theModel); theUniverse := theModel; theModel.initialize; end; procedure TBilliardDocument.DoMakeViews (forPrinting : Boolean); begin new(theView); failNil(theView); theView.ITBilliardView(self); end; procedure TBilliardDocument.DoMakeWindows; const theWinID = 1001; begin theWindow := NewSimpleWindow(theWinID, not kWantHScrollBar, not kWantVscrollBar, nil, theView); theWindow.setTitle('billiards game'); theWindow.Open; end; \end{cprog}\pascalfalse \caption{The class {\sf TBilliardDocument}}\label{TBilliardDocument} \end{figure} The view created by the method {\sf DoMakeViews} is an instance of the class {\sf TBilliardView}, shown in Figure~\ref{TBilliardView}. The billiard view maintains a pointer back to its associated document. The initialization method not only sets this pointer, but establishes the size of the view. The major tasks for the view are to redraw the image, and to respond to mouse clicks. These are accomplished by the methods {\sf Draw} and {\sf DoMouseCommand}, respectively. The latter is once more provided with a number of arguments that are ignored by our simple application, and returns a value indicating whether any special action should be taken to track the mouse (none, in this case). \begin{figure} \pascaltrue\begin{cprog} type TBilliardView = object(TView) myDocument : TBilliardDocument; procedure ITBilliardView (theDoc : TBilliardDocument); procedure Draw (area : Rect); override; function DoMouseCommand(var theMouse : Point; var info : EventInfo; var hysteresis : Point) : TCommand; end; procedure TBilliardView.ITBIlliardView (theDoc : TBilliardDocument); var viewSize : VPoint; begin myDocument := theDoc; SetVPt(viewSize, 450, 350); self.IView(nil, nil, gZeroVpt, viewSize, sizeFixed, sizeFixed); end; procedure TBilliardView.Draw(area : Rect); begin { set the global variable theUniverse to our data } theUniverse := myDocument.theModel; { the model knows how to draw itself } theUniverse.draw; end; function TBilliardView.DoMouseCommand(var theMouse : Point; var info: EventInfo; var hysteresis : Point) : TCommand; begin theUniverse := myDocument.theModel; { hit the cue ball to start it rolling } theUniverse.cueBall.energy := 20.0; theUniverse.cueBall.direction := hitAngle( theUniverse.cueBall.x - theMouse.h, theUnvierse.cueBall.y - theMouse.v); { then see what happens next } theUniverse.updateMoveableObject; DoMouseCommand := gNoChanges; end; \end{cprog}\pascalfalse \caption{The class {\sf TBilliardView}}\label{TBilliardView} \end{figure} Creating these three classes is all we need to do to produce a minimal Macintosh application. The application will permit multiple windows containing different instances of the billiard game to appear on the screen at once. Each window can be move or resized. The menu bar will be managed for for the application, allowing access to desk accessories and execution of common commands (such as the command {\sf quit} used to exit the application). The use of the MacApp classes also makes it easy to modify or extend the application. For example, to make each of the windows scrollable all that is necessary is to remove the {\sf not} from the constants in the call to {\sf newSimpleWindow}. To allow games to be saved and restored all that would be necessary is to add a pair of methods to the document class. Printing an image of the window can also be easily added. \clearpage \section*{Exercises} \begin{enumerate} \item This chapter has described three different types of application frameworks. For each of these describe a type of program for which the framework is better suited than either of the other two. \end{enumerate} \begin{thebibliography}{xxx} \bibitem[LaLonde 91]{pugh} Wilf R. LaLonde and John R. Pugh, {\em Inside Smalltalk}, Prentice-Hall, 1991. \bibitem[Linton 89]{interviews} Mark A. Linton, John M. Vlissides, and Paul R. Calder, ``Composing User Interfaces with InterViews,'' {\em Computer}, 22(2): 8-22, 1989. \bibitem[Wilson 90]{macapp} David A. Wilson, Larray S. Rosenstein and Dan Shafer, {\em Programming with MacApp}, Addison-Wesley, Reading, Mass. 1990. \end{thebibliography} \end{document} @EOF chmod 644 gui.tex exit 0