17.2.2 CLIM Operators for Graph Formatting

format-graph-from-roots [Function]	

Arguments: root-objects object-printer inferior-producer &ke y stream orientation cutoff-depth merge-duplicates duplicate-key duplicate-test generation-separation within-generation-separation center-nodes arc-drawer arc-drawing-options graph-type (move-cursor t )

Summary: Draws a graph whose roots are specified by the sequence root-objects . The nodes of the graph are displayed by calling the function object-printer , which takes two arguments, the node to display and a stream. inferior-producer is a function of one argument that is called on each node to produce a sequence of inferiors (or nil if there are none). Both object-printer and inferior-producer have dynamic extent.

The output from graph formatting takes place in a normalized + y -downward coordinate system. The graph is placed so that the upper left corner of its bounding rectangle is at the current text cursor position of stream . If the boolean move-cursor is t (the default), then the text cursor will be moved so that it immediately follows the lower right corner of the graph.

The returned value is the output record corresponding to the graph.

stream is an output recording stream to which output will be done. It defaults to *standard-output* .

orientation specifies the direction from root to leaves in the graph. orientation may be either :horizontal (the default) or :vertical . In LispWorks, it may also be :down or :up ; :right is a synonym for :horizontal and :down is a synonym for :vertical .

cutoff-depth specifies the maximum depth of the graph. It defaults to nil , meaning that there is no cutoff depth. Otherwise it must be an integer, meaning that no nodes deeper than cutoff-depth will be formatted or displayed.

If the boolean merge-duplicates is t , then duplicate objects in the graph will share the same node in the display of the graph. That is, when merge-duplicates is t , the resulting graph will be a tree. If merge-duplicates is nil (the default), then duplicate objects will be displayed in separate nodes. duplicate-key is a function of one argument that is used to extract the node object component used for duplicate comparison; the default is identity . duplicate-test is a function of two arguments that is used to compare two objects to see if they are duplicates; the default is eql . duplicate-key and duplicate-test have dynamic extent.

generation-separation is the amount of space to leave between successive generations of the graph; the default is 20. within-generation-separation is the amount of space to leave between nodes in the same generation of the graph; the default is 10. generation-separation and within-generation-separation are specified in the same way as the y-spacing argument to formatting-table .

When center-nodes is t , each node of the graph is centered with respect to the widest node in the same generation. The default is nil .

arc-drawer is a function of seven positional and some unspecified keyword arguments that is responsible for drawing the arcs from one node to another; it has dynamic extent. The positional arguments are the stream, the "from" node, the "to" node, the "from" x and y position, and the "to" x and y position. The keyword arguments gotten from arc-drawing-options are typically line drawing options, such as for draw-line* . If arc-drawer is unsupplied, the default behavior is to draw a thin line from the "from" node to the "to" node using draw-line* .

graph-type is a keyword that specifies the type of graph to draw. CLIM supports graphs of type :tree , :directed-graph (and its synonym :digraph ), and :directed-acyclic-graph (and its synonym :dag ). graph-type defaults to :tree when merge-duplicates is t ; otherwise, it defaults to :digraph .

The following is an example demonstrating the use of format-graph-from-roots to draw an arrow. Note that draw-arrow* is available internally.

(define-application-frame graph-it ()
  ((root-node :initform (find-class 'clim:design)
              :initarg :root-node
              :accessor root-node)
   (app-stream :initform nil :accessor app-stream))
  (:panes  (display :application
                    :display-function 'draw-display
                    :display-after-commands :no-clear))
    (horizontally () display))))
(defmethod draw-display ((frame graph-it) stream)
  (format-graph-from-roots (root-node *application-frame*)
                           :stream stream
                           #'(lambda (stream from-object
                                             to-object x1 y1
                                             x2 y2 
                               (declare (dynamic-extent
                               (declare (ignore from-object
                               (apply #'draw-arrow* stream
                                      x1 y1 x2 y2 drawing-options))
                           :merge-duplicates t)
  (setf (app-stream frame) stream))
(define-presentation-type node ())
(defun draw-node (object stream)
  (with-output-as-presentation (stream object 'node)
                                (stream :shape :rectangle)
                                (format stream "~A"
                                        (class-name object)))))
(define-graph-it-command (exit :menu "Exit") ()
  (frame-exit *application-frame*))
(defun graph-it (&optional (root-node (find-class 'basic-sheet))
                          (port (find-port)))
  (if (atom root-node) (setf root-node (list root-node))) 
  (let ((graph-it (make-application-frame 'graph-it
                                           :port port)
                                          :width 800
                                          :height 600
                                          :root-node root-node)))
    (run-frame-top-level graph-it)))

CommonLisp Interface Manager 2.0 User's Guide - 18 Mar 2005