\documentstyle[local,twoside,pce,psfig,logo,11pt]{report} \makeindex %\includeonly{draw} \begin{document} \begin{titlepage} \titlepageheader \vfil\vfil\vfil \begin{center} {\Huge \bf PceDraw \\[3mm] \LARGE An example of using PCE-4} \\[1.5cm] {\large \it Jan Wielemaker} \\[3mm] {\large jan@swi.psy.uva.nl} \end{center} \vfil \begin{quote} This document describes the design and implementation of PceDraw, a drawing tool written in PCE-4/Prolog. PceDraw exploits many of the features of PCE and is written according to our current ideas on using PCE/Prolog. \end{quote} \vfil \vfil \end{titlepage} \pagestyle{esprit} \newcommand{\bottomleft}{\mbox{}} \newcommand{\bottomright}{\mbox{}} \tableofcontents \chapter{Introduction} One of the aims of writing PceDraw is to provide users of PCE who have made their first steps in using the system with an example that explains how large applications can be realised using PCE/Prolog. This document motivates the decisions taken to arrive at PceDraw, both at the level of the overall design and at the level of the detailed design and implementation. This document is part of the documentation of PCE-4. The complete documentation consists of: \begin{itemize} \tick{Programming in PCE/Prolog \cite{PCE:Prolog}} This document is an introduction to programming in PCE/Prolog. It provides the background material to understand the other documentation. \tick{PCE-4 Functional Overview \cite{PCE:overview}} This document provides an overview of the functionality provided by PCE. It may be used to find relevant PCE material to satisfy a particular functionality in your program. \tick{PCE-4 User Defined Classes Manual \cite{PCE:udc}} This document describes the definition of PCE classes from Prolog. PceDraw is implemented as a set of user-defined classes. \tick{The online PCE Reference Manual} The paper documents are intended to provide an overview of the functionality and architecture of PCE. The online manual provides detailed descriptions of classes, methods, etc.\ which may be accessed from various viewpoints. \cite{PCE:Prolog} describes how to use the online manual. \end{itemize} This document aims at PCE users who have understood the basics of PCE and have some experience with Prolog. In its final context (as an appendix) the tutorial should provide the necessary material. When new constructs are introduced in this document they are often explained. It is adviced to read chapter~\ref{sec:design} first and proceed with the introduction and the first section of chapter~\ref{sec:sources}. The remaining material may be used as a set of examples. At the end of this document is an index, indicating references to methods, predicates and files discussed. Chapter~\ref{sec:design} explains the overall design of PceDraw. Chapter~\ref{sec:sources} contains a brief overview of the organisation of the sources, followed by the annotated sources. Two chapters that will be part of the tutorial have been added as appedices to this manual. The first deals with style conventions for the definition of classes and the second with using global object references (e.g. @same_center). \chapter{Design} \label{sec:design} \section{Functional overview} PceDraw is a drawing tool for creating structured diagrams: flow-charts, diagrams capturing architecture, etc. In this kind of diagrams there is usually a small number of reoccurring shapes that have to be linked to each other. For this reason, the editor should allow the user to create/save/load a library of prototypes. A typical example of such a prototype is a box with centered text. Lines between shapes often represent semantical relations and therefore should remain connected to the shape if the shape is moved/resized and should be destroyed when the shape is deleted. This document aims at the software design and implementation of PceDraw and therefore the requirements analysis and functional specification is very brief. For getting a clear view on the functionality it is adviced to run PceDraw. It can be started from xpce by the command: \begin{code} 1 ?- pcedraw. \end{code} PceDraw has been designed from these principles. The initial tool consist of three areas: the drawing area itself, a menu with available prototypes and a general command and feedback area. Besides creating, moving, resizing, etc., the tool must be able to edit shape attributes such as the thickness of the drawing pen and the font. This functionality is dealt with by an attribute editor which can be launched in a separate toplevel window. PceDraw provides two kinds of menu's. All commands are available through pulldown menus in the `command area' of the tool. Frequently used commands on a single shape are also available through a popup-menu associated with each shape. This approach has several advantages. The pulldown menus provide a place where all functionality can be found (except selecting a prototype and operations performed via direct-manipulation such as selecting, moving and resizing shapes), while the popup menus allows for fast access to the commonly used commands. \index{keyboard accelerators} The current version of PceDraw does not support keyboard accelerators. Defining accelerators should be supported by PCE's dialog primitives. This will be implemented later. \section{Realisation in PCE} After the functionality is specified, PCE primitives that serve as a starting point for the realisation be selected. It is hard to tell how this should be done. PCE contains a large amount of functionality that can be combined in several ways. Examples, the tutorial and the online manual (manpce/[0-1]) are the starting point. Below is a brief list with the main choices for PceDraw. See the various sourcefiles in chapter~\ref{sec:sources} for details. \begin{shortlist} \tick{Overall tool} A {\em frame} is a collection of windows and provides an ideal starting point for the overall tool. \tick{Drawing area} A {\em picture} is a window indended for displaying arbitrary graphical objects. \tick{Prototype menu} Two possibilities: 1) {\em dialog} + {\em menu} + {\em menu_item} or 2) {\em picture} + {\em bitmap}. See discussion in `menu.pl'. \tick{Command area} A {\em dialog} with a list of pulldown menus organised in a {\em menu_bar} and a {\em label} for feedback messages. \tick{Shapes} Appropriate PCE graphical (box, ellipse, text, line, etc.). \tick{Prototypes} A {\em device} is a collection of graphicals that can be manipulated as a single unit. The <-klone method can be used to create instances. \tick{`Settings' (or attribute) editor} A {\em dialog} window with appropriate {\em dialog_items} for the various settings. \tick{(Direct) manipulation of shapes} {\em recognisers} can be attached to the various shapes. We can start from the various standard {\em gestures} defined in PCE. PceDraw can operate in various modes (select, create, edit_text, etc.). A mode attribute can be attached to the drawing area, where it can easily be found from the recognisers, so they can use it as a condition. \tick{Load and Save} Both prototypes and drawings must be saved and loaded to/from Unix files. This can be realised using PCE's behaviour `Object ->save_in_file' and `File <-object'. \end{shortlist} \subsection{Creating an application} After we have selected the PCE building blocks from which to start, we have to extend them so that they fulfill our exact needs and cooperate to form the drawing tool. There are two ways to do this. The first is to regard PCE as a class/object library and extend/combine objects via `free-style' Prolog code. In this case our entire tool is (from the outside) a collection of Prolog predicates. The second possibility is to create subclasses from the basic PCE classes. Using the latter approach, the entire tool is a class of which an instance is created. What are the advantages of both approaches? We will look at them from an example. Suppose we have a drawing area and displaying an object on it should change a `modified' attribute associated with the drawing area. The PCE class picture is our starting point. Class picture does not have an instance variable `modified', so our task is to add such a variable and provide means to display an object on it and set the modified attribute. \subsubsection{Using PCE as a library} When using PCE as a library, the predefined objects and classes of PCE are regarded as a library of functionality we can access via the Prolog predicates new/2, send/[2-12] and get/[3-13]. There are two ways to modify or extend the behaviour of an object from a standard PCE class. The first is to write Prolog predicates that perform certain operations on the object(s). The second is to use PCE's object-level programming mechanisms to extend the object. Below is the code that results from using Prolog predicates. \begin{code} create_canvas(P) :- new(P, picture), send(P, attribute, attribute(modified, @off)). display_canvas(P, Graphical, Point) :- send(P, display, Graphical, Point), send(P, modified, @on). \end{code} Although this technique does not create a new (PCE) class, it does create a new `conceptual' kind of object: the canvas. `Display' is a method of this new kind. Depending on whether the method is defined in the PCE class or in Prolog, the behaviour should be invoked either via send/[2-12] or with the Prolog predicate: \begin{code} 1 ?- send(P, selection, @nil). 2 ?- display_canvas(P, box(30,30), @default). \end{code} The syntactical difference makes it clear whether the action initiates a Prolog predicate ---and thus a part of the application--- or a method of the PCE library. A programmer using this conceptual kind of object must be aware whether the method is part of PCE or part of the extension. Calling the raw PCE method might lead to inconsistencies: if the user invokes \begin{code} 1 ?- send(P, display, box(30,30)). \end{code} the contents of the canvas will be modified, but the modified attribute won't change. \header{Extending the object} The second possibility uses programming PCE at the object level. Methods can be assigned to objects similiar to classes. The method object consists of three parts: the name or selector, the type specification and the action or message. The type specification is a vector with the same number of arguments as expected by the method. Each element of the vector specifies the corresponding type. See the online manual, topic `types'. While a message implementing a method is executed, @arg1 is bound the the first argument provided, @arg2 to the second, etc. See also `Object ->send_method'. \begin{code} create_canvas(P) :- new(P, picture), send(P, attribute, attribute(modified, @off)), send(P, send_method, send_method(display, vector(graphical, '[point]'), block(message(P, send_class, display, @arg1, @arg2), message(P, modified, @on)))). \end{code} Using this solution, the user of the canvas does not need to know that the ->display method of the raw PCE object has been redefined. The new object has a method named ->display which not only takes care of displaying the object, but also updates the modified attribute. Remaining problems are: \begin{shortlist} \item PCE object are created using new/2, while application objects area created via a Prolog predicate. \item From the outside one cannot tell easily whether the object is a raw PCE object or a modified one. \item If many instances are created, each of them will have method objects attached to them. \item Writing code like this requires the user to know PCE's programming classes (block, if, and, etc.). \item If the implementation cannot be handled by PCE's programming classes a message to @prolog is necessary. In this case the implementation will be spread over two locations. \item The code is attached to the object. If ---during debugging--- this code needs to be changed there is little alternative then destroying the object and recreating it. \item If the object is saved using `Object ->save_in_file' or kloned using `Object <-klone', the code part is saved/kloned as well. \item It is difficult to read and write. \end{shortlist} Object level programming is not used intensively in PCE, but in some situations it is the best solution. \subsubsection{Extending PCE} The alternative provided by PCE-4 is to create a new class for the canvas. Creating a class is done using the normal PCE interface primitives new/2, send/[2-12] and get/[3-13], but a Prolog defined preprocessor based on the Edinburgh Prolog primitive term_expansion/2. This is our solution based on classes. The pce_begin_class/3 call creates class canvas as a subclass of (the predefined) class picture. Next, it asserts (using asserta/1) a clause for term_expansion/2 that will convert the class declarations. The optional last argument is the summary documentation of the class. The pce_end_class/0 call terminates the declaration by removing the clause for term_expansion/2. The variable/4 declaration is expanded to attach a new instance variable for the class. The arguments are the name, the type, the access rights and the optional summary documentation. The \verb$:->/2$ is expanded to define a send method for the class. The first argument is `self'. The remaining arguments are of the form \mbox{`PrologVar:PceType'}. The body may start with a line '\verb$"...."::$', which is recorded as the summary documentation of the method. The remainder is plain Prolog code. The method ->initialise is called from the PCE virtual machine (VM) to initialise the instance from the arguments provided with new/2. It should be there if the initialisation should do something in addition to the initialisation of the super-class. When defined, the ->initialise method should perform the initialisation of the super_class: \begin{code} send(Self, send_super, initialise, ...) \end{code} In this example, the variable <->modified must be initialised to @off. The ->display method as defined below redefines the built-in method of class picture by setting the modified flag. \begin{code} :- pce_begin_class(canvas, picture, "Drawing area"). variable(modified, bool, both, "Has diagram been modified"). initialise(C) :-> send(C, send_super, initialise), send(C, modified, @off). display(C, Gr:graphical, Pos:[point]) :-> "Display graphical and set modified":: send(C, send_super, display, Gr, Pos), send(C, modified, @on). :- pce_end_class. \end{code} After this, we can use the class as if it were a predefined PCE class: \begin{code} ... new(C, canvas), send(C, display, box(30,30)), ... \end{code} User defined classes is one of the three possibilities to build an application in PCE. It does not have the disadvantages of introducing `conceptual' kinds using Prolog predicates, neither the disadvantages of using object-level programming. Complete applications however normally consist of a large number of objects with sometimes only slightly different behaviour. Using classes for each of these categories makes it difficult to avoid large amounts of awkward classnames. For this reason, using Prolog predicates or object level programming can be a good alternative for defining a class. It is adviced to use these techniques only for local communication and use class-level programming for global communication between components of the application. \subsubsection*{Extending vs. creating classes} PCE/Prolog allows both for extending the behaviour of existing classes and defining new ones. Extending classes implies redefining them, and should first of all be used to (temporary) overcome ommisions in the PCE system itself. Extending behaviour of existing classes may easily affect consistency of large applications, so be careful. For one case, extending PCE classes may be considered. Suppose we have an application that creates various subclasses of the various predefined subclasses of class graphical (e.g. box, circle, line) and all these classes need to have some common method that can be implemented at the level of the PCE class graphical. In this case it might be desirable to implement the method there instead of at each subclass. If you decide to do so, it is adviced to give the method a name that clearly indicates the application for which it was introduced, so no conflicts with other applications or future PCE extensions is to be feared.% \footnote{An alternative (and in this case better) solution to this problem would be to introduce multiple inheritance. Multiple inheritance however introduces various conceptual problems and in the current implementation of PCE unresolvable technical ones.} Creating new classes however does not affect the consistency of the system and provides a clean way to extend PCE. \section{Class organisation and communication} \subsection{Overall tool communication} The application as a whole is represented by an instance of class `draw', which is a subclass of the PCE class frame. Class draw serves as an overall manager of the various parts of the drawing tool. Class frame forms an ideal starting point to do this: \begin{shortlist} \item Any graphical object (and almost anything in such a tool is a graphical object or is closely related to one) can easily find the reference to the tool as a whole using `Graphical <-frame'. \item Class frame can easily find all its parts using `Frame <-member'. \end{shortlist} For this reason, the instance of class frame is the ideal part to support communication. For example, feedback can be centralised by defining a method ->feedback on the frame. Now, any graphical object can give feedback by doing: \begin{quote} send(Myself?frame, feedback, 'I just did this'). \end{quote} \subsection{Drawing area and shapes} Picture and graphical are a communication couple. The drawing area of PceDraw is realised by class draw_canvas which is a subclass of picture. The various shapes that can be drawn are subclasses of closely related standard graphical classes (e.g. box, line). The pair canvas and shape adds responsiveness to user-events, maintenance of changes, etc. to the standard interaction between picture and graphical. \subsection{User Events (Shapes and gestures)} Shapes define the `Shape ->event' behaviour by forwarding the event to a reusable `gesture' object. A `gesture' is an object that allows for the management of a sequence of button-events, starting with a mouse-down and ending with the corresponding mouse-up. PCE defines several standard gestures. The file gesture.pl creates subclasses to implement the specific user-interface needed by PceDraw. \chapter{The Sources} \label{sec:sources} The application is subdivided into a number of files, each of which is a Prolog module file and defines a number of PCE classes that serve a similar role in the overall application. We use the Prolog module system to avoid possible name-conflicts with other packages for predicates used to support the methods. Below is an overview of the files. \begin{shortlist} \tick{draw.pl} Defines the toplevel predicates and the class `draw', of which a drawing tool is an instance. Class draw is a subclass of the PCE class `frame' \tick{canvas.pl} Defines class `draw_canvas'; a subclass of class picture. It is the drawing area of the editor. \tick{shapes.pl} Defines the shapes that can be drawn on the canvas. These shapes are small extensions to standard PCE classes. They add handles for connections and handling user events. \tick{gesture.pl} Defines subclasses of the PCE gesture classes. These gestures are linked to the shapes to process user events. \tick{menu.pl} Defines the menu at the right of the drawing area and the (prototype) icons displayed on them. \tick{attribute.pl} Defines the attribute editor that can be used to modify the attributes of graphical objects. \tick{align.pl} Defines the automatic alignment functionality. This file is not included in the sources as it adds little to the understanding of xpce. \end{shortlist} \header{Conventions} Each source file is given in a section named ``Source file name''. The actual code is preceded by small line numbers at the left margin. \include{draw} \include{canvas} \include{shapes} \include{gesture} \include{menu} \include{attribute} \chapter{Conclusions} In this document we presented a medium-sized application to illustrate how applications can be designed and realised using PCE. We have tried to make the design process and design decissions explicit. No doubth it is possible critise the code and decissions made. Nevertheless, we hope the sources of PceDraw form a valuable starting point for programming in PCE/Prolog. The drawing tool presented in this document may be used as such. It should be noted however that the functionality is incomplete. Notably editing prototypes is limited. \appendix \chapter{Programming Style} As O'Keefe argues in ``The craft of Prolog'' \cite{Keefe:90}, using a `good' programming style is not something optional. PCE/Prolog as presented in this document is definitely something different then Prolog with some additional library predicates. PceDraw as presented here is an example of what we currently believe to be good programming style. \section{Organisation of sourcefiles} The PCE class compiler allows for the definition of multiple classes in one file. Quintus Prolog compatible Prolog systems allow a file represent at most one Prolog module. What is the best way to organise your sources? There seem to be two reasonable solutions. Each file either represents a Prolog module and one PCE class, or a bundle of Prolog predicates. Files of the first type generally do not export any predicates. All communication is done by sending messages to instances of the class defined in the file. Files defining normal Prolog predicates do have an export list (otherwise we can't reach their contents). These predicates can be imported as usual. The second possibility is to define (small) classes that belong to each other or the same category in the same file (and module). Internally, these classes may communicate both using Prolog calls and by sending messages. \section{Organisation of a class definition} Below is a list of the various sections that make up a class definition. Except for the header and footer, all the sections are optional. Technically (currently) no ordering between the other sections is required. For clarity it is adviced to use a standard schema for all your classes. \begin{shortlist} \tick{Header} This is just the \verb$:- pce_begin_class(Class, Super).$ declaration. \tick{Instance variable declarations} The variable/[3-4] declarations for additional instance variables. \tick{X-resource declarations} The resource/[3-4] declarations that provide access to the X-resource database. All aspects that are arbitrary default choices of the UI style should be declared via resources. This enhances clarity of the choices and allows the user to tailor the UI. \tick{Handle declarations} The handle/4 declaration to create handles for connections. \tick{Initialisation method} The initialisation method of a class normally comes first. It is invoked by the PCE vitual machine (VM) operation new() that creates an instance. Messages and predicates that only support the initialisation method (if it is very complicated; long initialisation methods can often be found for dialog windows) are defined right below the method. \tick{Unlink method} The unlink method is invoked from the PCE VM operation that destroyes an instance. It is normally declared right after the initialisation method. \tick{Other reserved methods} PCE's internals call various other methods that may be redefined. Examples are `Graphical ->geometry', `Graphical ->event' and `Gesture ->initiate'. These are normally declared before the other methods. \tick{Public functionality} With this, we refer to methods that facilate the communication with other parts of the application. \tick{Local utilities} Methods and Prolog predicates that are used from various places within this class definition are placed at the bottom. The reason for this is that one is usually not interrested in these things. \tick{Footer} The \verb$:- pce_end_class.$ declaration terminates the declaration of the class. \end{shortlist} Section~\ref{sec:class-template} provides a template for the class declaration. \subsection{Class definition template} \label{sec:class-template} Italic words indicate text that should be filled in by the user. `...' denotes ``more of these''. \newcommand{\F}[1]{{\it #1}} \begin{pcecode} \tt\obeyspaces :- pce_begin_class(\F{Class}(...\F{TermDescriptionArguments}...), \F{Super}, "\F{Documentation}"). variable(\F{Name}, \F{Type}, \F{Access}, "\F{Documentation}"). ... resource(\F{Name}, \F{Type}, \F{Default}, "\F{Documentation}"). ... handle(\F{X_FORMULA}, \F{Y_FORMULA}, \F{Kind}, \F{Name}). ... /******************************** * CREATE/UNLINK * ********************************/ initialise(\F{Self}, ...\F{Arg}:\F{Type}...) :-> "Initialise from \F{Arguments}":: \F{CheckArguments}, send(\F{Self}, send_super, initialise, ...\F{SuperInitArgs}...), \F{SpecificInitialisation}. unlink(\F{Self}) :-> "\F{Documentation}":: \F{SpecificUnlink}, send(Self, send_super, unlink). /******************************** * RESERVED METHODS * ********************************/ event(\F{Self}, Ev:event) :-> "\F{Documentation}":: ( send(\F{Recogniser}, event, Ev) -> true ; send(\F{Self}, send_super, event, Ev) ). ... /******************************** * PUBLIC METHODS * ********************************/ \F{Sendmethod}(\F{Self}, ...\F{Arg}:\F{Type}...) :-> "\F{Documentation}":: \F{Implementation}. \F{Getmethod}(\F{Self}, ...\F{Arg}:\F{Type}..., \F{Result}) :<- "\F{Documentation}":: \F{Implementation}. /******************************** * UTILITIES * ********************************/ \F{Methods}. ... \F{Prologpredicates}. ... :- pce_end_class. \end{pcecode} \section{Choosing names} Apart from the Prolog predicates and variables for which any Prolog oriented naming schema applies, various other objects have to be named while using PCE/Prolog. Names for PCE objects have either global scope or local scope to the class they are associated with. Names for classes and global objects are global. Names for selectors, variables and resource are local to their class. For all these names, the following should apply: \begin{shortlist} \item Names with global scope over the entire process should be short when they denote some very basic concept of the application. Otherwise they are best prefixed with some indication of the category they belong to (e.g. \verb$draw_$ for all global names related to PceDraw). \item Names with local scope (selectors, variables and resources) have meaningful names. In general they should not be abbreviations. When they denote a general operation, they should be named to this operation (e.g. `quit', `relate'). When they denote something very specific, something that can be used only under some non-frequently occuring situation, they should have long names. \end{shortlist} \section{Predicates or methods?} When writing in PCE/Prolog, there is usually the choice between writing a method and invoking this using send[2-12] or get/[3-13] or writing Prolog predicates and calling these directly. When using user-defined classes as the basis for structuring an application, the following rules apply: \begin{shortlist} \item Communication between classes defined in different source-files is always using messages. This way the overall structure of the application is based upton one mechanism. \item Within one sourcefile Prolog based activation/calling may be used. This however should be limited to cases where: \begin{enumerate} \item Data that is not easily converted to PCE data is to be passed as arguments. \item Prolog backtracking should be exploited. \item Communication is very time critical. \item It implies a private unitily. \end{enumerate} \end{shortlist} \section{Method arguments} Arguments to methods are determined by there location in the argument vector. PCE distinguishes between obligatory and optional arguments (i.e. arguments that may be @default). To avoid having to look in the manual continuously it is necessary to define some standards for argument ordering. The rules used inside PCE have never been stated explicitely and compatibility considerations sometimes leaded to non-intuitive arguments. Below is an attempt to make them explicit. \begin{itemize} \item Do not use too many obligatory arguments. If possible try to limit the number of obligatory arguments to 1 or 2. `Name' or similar arguments in general come first. `Values' (e.g. `dialog_item <->selection') come second. If there is a sensible default or the user might not want to specify the value because it will be filled in later, make the argument optional. Example: initialising a line does not require any arguments. Start and end-points default to (0,0). This is useful as (notably for defining links), it is not unlikely the user wishes to create a line and define the start and end-point later. \item Define sensible defaults the optional and order them in decreasing `likelyness' the user might wish to overrule the default. \end{itemize} \section{Layout conventions} The considerations for layout of PCE/Prolog programs do not differ very much from those for ordinary Prolog programs. PCE/Prolog programs tend to use deeply nested complex terms, notably while specifying message objects. The normal rules for breaking long terms apply. \bibliographystyle{name} \bibliography{pce} \printindex \end{document}