Fizzy

Draw diagrams using pre-defined "Stencils" (or create your own stencils). Inspired by Visio.

For example, an organisation chart has boxes with structured content (a name, and role etc). The boxes can be connected by lines. If you move a box, the connecting lines are automatically adjusted.

Stencils are defined using something similar to a spreadsheet, where many values are expressions, which depend on other parts of the spreadsheet. This allows the shapes to behave intelligently. For example, a box may resize itself to ensure its contents fit in nicely.

Progress

Still in the very early stages of development. No GUI code has been written yet (which may sound weird for a graphical application). However, testing GUIs is much harder than non-GUI code, so I am concentrating on the core, non-GUI code first,

I have nearly 500 unit tests.

Design

Written in Kotlin, and using JavaFX for the GUI.

The linchpin of the system is the class Prop and its many sub-classes. These are similar to JavaFX's Property. They fire events to listeners when their value changes, and one Prop can be dependent on another. Every aspect of a shape is defined by Props. Props can be simple constants, calculated values or expressions.

Expressions

An expression contains a string which is evaluated. The syntax is Fizzy-specific. The data types supported are :

  • Double
  • String
  • Boolean
  • List
  • Vector2 - x : Double, y : Double
  • Dimension - Defines a length, including its units. e.g. 10mm == 1cm == 0.1m.
  • Dimension2 - x : Dimension, y : Dimension (most attributes of a Shape, use this).
  • Angle - Avoids the confusion between degrees and radians. e.g. 180deg == PI (which is a constant of type Angle) ~= 3.1415rad.

Fizzy's model objects, such as Shape, Page and Document can also be used within expressions. Notable omissions are Date and URL, and will be addressed later when Fizzy is more mature.

As well as all the usual operator such as + - etc, expressions can use functions, methods and fields. The precedence of operators is based on Kotlin.

There are no looping structures. These are **expressions**, not code blocks!

Example Expressions :

  • Dimension2( 10mm, 2cm ) : creates a Dimension2 constant
  • Dimension2( 10mm, 2cm ).X : returns a Dimension (10mm)
  • Dimension2( 10mm, 2cm ) / 2 : returns Dimension2( 5mm, 1cm )
  • Dimension2( 1m,1m ).Angle.degrees : returns the Double 45
  • Dimension2( 1m, 0cm ).rotate( 90 deg ) : returns Dimension2( 0m, 1m )
  • Parent.Size.Length : Returns a Dimension (the parent shape's diagonal measurement)

Many parts of a Shape's spreadsheet contain lists. These can be accessed in a spreadsheet like way :

  • Geometry1.Point4 - Returns the cell's value at column "point" and row "4" from the Geometry1 spreadsheet.

Note that row indicies are 1-based (as opposed to the zero-based index of traditional arrays). Internally, this is doing : myShape.geometry0.parts3.point.

Conventions

  • Method, functions and conversion operators (such as mm and deg) start with a lower case.
  • Everything else starts with a capital letter.
  • Predefined Constants (such as PI) are all upper case. However, true and false are exceptions, and are all lower case.

Testing

Automated testing of a GUI is much harder than "regular" code, so I want as many tests to be GUI-free.

In fact I plan on implementing the GUI in such a way that most aspects of editing a diagram can be written and tested by mocking a GUI context.