A rough system design

This system design is based on the Requirements that were initially stated. Note that this is in no way a solid or complete design. It's just more or less a sketch for an object model.

Here's our system design, broken down per class with their important properties and member functions:
  • class AreaPart
    • method: OverlapsWith(Rect?) ?
    • method: IsHit(PointF) ?
  • class Area
    • property: areaparts (list of elements of type AreaPart)
    • method: OverlapsWith(Rect?) ?
    • method: IsHit(PointF) ?
  • class Element
    • property: area (type Area)
    • property: isSelected (type bool)
    • property: isHighlighted (type bool)
    • method: Render()
  • class Connector
    • property: area (type Area)
    • property: owner (type Node)
    • property: group (type int?)
  • class Node (inherited from Element)
    • property: connectors (a list with elements of type Connector)
    • method: CanConnect( Connector, Connector )
  • class Cable (inherited from Element)
    • property: from (type Node)
    • property: to (type Node)
    • method: RecalculateArea()

  • class InteractionStyle
  • class InteractionStyleDefault (inherited from InteractionStyle)
  • class InteractionStyleMaya (inherited from InteractionStyle)
  • class Grid
    • property: spacing (?)
  • class View
    • property: zoomFactor (type float)
    • property: offset (type PointF)
  • class Layer
    • property: visible (type bool)
    • property: elements (list with elements of type Element)
  • class WorkspaceView
    • property: layers (list with elements of type Layer)
    • property: interactionstyle (of type InteractionStyle)
    • property: selection (list with elements of type Element)
    • property: view (type View)

Design explanation

Areas

Each Element instance must have an area. An area defines the area that is used on screen for rendering AND the area that is used for detecting mouse hits and selection detection. Each area consists of several "AreaParts". These are simply primitive shapes which alltogether define the area taken by the element. We will provide an implementation for some default areaparts such as a RectanglePart and a CirclePart. The rest is up to the user.

Nodes and connectors

Each node has a variable number of connectors. To each connector a variable number of cables can get attached. But a user will probably want to give some special meaning to connectors, such as "output" and "input". Such a meaning often limits the type of cables that can get connected to such connectors. To support this constraining of connecting cables we:
  • Provide each Connector with a "group index" property
  • Provide a "CanConnect(Connector, Connector)" method in the Node class that can be overwritten by a user for implementing his own cabling constraints (based on the groupindices of the connectors).

Selection and highlighing

Each element knows that it is selected or not and that it is highlighted or not. Our workspace view itself also contains a list of all selected elements, this is for ease of access. The "highlight" state of an element doesn't have any effect, an is only monitored for visual reasons (it can be used in a overridden Draw method).

PS. An element is "highlighted" when the user has the mousecursor positioned above the area of the element.

Interaction styles

All input mapping is performed through the InteractionStyle instance that our workspaceview has. So instead of directly performing a MouseButton == Left comparison in a Mouse event handler to determine that the user wants to start panning, we simply ask the InteractionStyle instance if the user "intends to start panning", given the provided mouse and keyboard state.

We also provide one or two default interaction styles.

Customization
  • The Node and Cable classes should be subclassed by the user to implement specific nodes, for:
    • Custom drawing functionality, since the Node and cable classes by default are not drawing anything.
    • Providing an area instance, for defining the area occupied by the node.
  • The InteractionStyle class can be subclassed, to implement different interaction styles.

Moving

Only nodes can be moved by the user, cables are not moveable (you'll have to move de nodes!). Moving a node actually forces its Area to be updated, together with all the connected cables' areas. The recalculation of these areas should be done in a method called RecalculateArea() in the Cable which the user has to override.

Open problems
  • When the user is able to define/create his own Node subclasses, how do we get instances of these classes in our view. How do we duplicate them? How do we instantiate them upon deserialization?

Last edited Dec 24, 2008 at 11:03 AM by Gloei, version 7

Comments

WalterTamboer Dec 23, 2008 at 9:07 PM 
InteractionStyle will be some sort of Action Map. What do we do with key combinations that a user defines? What if the user wants custom actions?