parent previous next question (Smalltalk Textbook 46)

EngiClassVertex & EngiClassBranch

I'd like to show you an example use of the grapher libraries covered in the last few sections. 'EngiClassVertex' and 'EngiClassBranch' are used by the graphical class browser (described in the next section) to display and operate on inheritance hierarchies of Smalltalk classes. Source is in Appendix 30.

'EngiVertex' is the super class of 'EngiClassVertex', and 'EngiBranch' is the super class of 'EngiClassBranch'. Class definitions are:


Program-46-1: (EngiVertex, EngiClassVertex, EngiClassBranch)
-----------------------------------------------------------------
EngiVertex subclass: #EngiClassVertex
    instanceVariableNames: 'className classIcon '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Engi-Inheritance'
-----------------------------------------------------------------
EngiBranch subclass: #EngiClassBranch
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Engi-Inheritance'
-----------------------------------------------------------------

A node which represents a class has two instance variables. 'className' holds the name of the class as a Symbol, and 'classIcon' stores what is to be visually displayed. The super class 'EngiVertex' leaves displaying a node as an icon to subclasses because it only knows the position of the node in the graph as 'vertexPoint' and the size of the node as 'vertexExtent'.

'computeBounds' returns a node's display area:


Program-46-2: (EngiVertex; computeBounds)
-----------------------------------------------------------------
computeBounds
    | bounds |
    bounds := classIcon bounds.
    bounds := bounds align: bounds origin with: self vertexPoint.
    ^bounds
-----------------------------------------------------------------

The top-left corner of 'classIcon bounds'is placed at 'vertexPoint' to display an icon. The class name string with a space character at both ends is stored in 'classIcon' as an instance of 'ComposedText' shown in the following method. Therefore 'vertexExtent' (node size) is the same as the size of the instance of 'ComposedText'.


Program-46-3: (EngiClassVertex; className:)
-----------------------------------------------------------------
className: aSymbol
    className := aSymbol.
    classIcon := (' ' , aSymbol asString , ' ') asComposedText.
    classIcon gridWithLead: 0.
    self vertexExtent: classIcon bounds extent
-----------------------------------------------------------------

The display method for a class node is:


Program-46-4: (EngiClassVertex; class node, displayStrokedOn:at:)
-----------------------------------------------------------------
displayStrokedOn: graphicsContext at: aPoint
    | aRectangle |
    aRectangle := self vertexPoint extent: self vertexExtent.
    aRectangle := (aRectangle translatedBy: aPoint) rounded.
    graphicsContext paint: self strokeColor.
    graphicsContext lineWidth: self lineWidth.
    classIcon displayOn: graphicsContext at: aRectangle origin
-----------------------------------------------------------------

Arcs need no instance variables to be able to draw themselves. They just draw a zig-zag line from the connecting point of the first vertex to the connecting point of the second vertex. This assumes a left-to-right ordering. To check this, move a vertex to the left of its superclass and see how the connection is drawn.


Program-46-5: (EngiClassBranch; arc, displayStrokedOn:at:)
-----------------------------------------------------------------
displayStrokedOn: graphicsContext at: aPoint
    startPoint := (self startPoint + aPoint) rounded.
    endPoint := (self endPoint + aPoint) rounded.
    graphicsContext paint: self strokeColor.
    graphicsContext lineWidth: self lineWidth.
    centerPoint := startPoint + (endPoint - startPoint // 2).
    graphicsContext
        displayLineFrom: startPoint
        to: centerPoint x @ startPoint y.
    graphicsContext
        displayLineFrom: centerPoint x @ startPoint y
        to: centerPoint x @ endPoint y.
    graphicsContext
        displayLineFrom: centerPoint x @ endPoint y
        to: endPoint
-----------------------------------------------------------------

The connecting points are defined as:


Program-46-6: (EngiClassBranch; startPoint, endPoint)
-----------------------------------------------------------------
startPoint
    startVertex isNil ifTrue: [^Point zero].
    ^startVertex bounds rightCenter
-----------------------------------------------------------------
endPoint
    endVertex isNil ifTrue: [^Point zero].
    ^endVertex bounds leftCenter
-----------------------------------------------------------------

'EngiClassVertex' (class node) and 'EngiClassBranch' (class arc) are now complete. They were easy to implement because their super classes provided a framework for their data and behavior.

In the next section I will implement 'classGraph' and 'calssModel' to let you browse the graphical class inheritance hierarchy.


parent previous next question
Copyright (C) 1994-1996 by Atsushi Aoki
Translated by Kaoru Rin Hayashi & Brent N. Reeves