\appendix

Syntax Quick Reference {#syntax-quick-reference}

Literals and Expressions

// Literals:
123      // Int
123.0    // Double
"Hello!" // String
true     // Boolean

// Math:
10 + 2   // Int + Int    = Int
10 + 2.0 // Int + Double = Double
10 / 2   // Int / Int    = Double

// Boolean logic:
true && false // logical AND
true || false // logical OR
!true         // logical NOT

// String concatenation:
"abc" + "def" // String
"abc" + 123   // auto-conversion from Int to String

// Method calls and infix operators:
1.+(2)    // method call style
1 + 2     // infix operator style
1 + 2 + 3 // equivalent to 1.+(2).+(3)

// Conditionals:
if(booleanExpression) expressionA else expressionB

// Blocks:
{
  sideEffectExpression1
  sideEffectExpression2
  resultExpression
}

Value and Method Declarations

// Value declaration syntax:
val valueName: SomeType = resultExpression // declaration with explicit type
val valueName = resultExpression           // declaration with inferred type

// Method with parameter list and explicit return type:
def methodName(argName: ArgType, argName: ArgType): ReturnType =
  resultExpression

// Method with parameter list and inferred return type:
def methodName(argName: ArgType, argName: ArgType) =
  resultExpression

// Multi-expression method (using a block):
def methodName(argName: ArgType, argName: ArgType): ReturnType = {
  sideEffectExpression1
  sideEffectExpression2
  resultExpression
}

// Method with no parameter list:
def methodName: ReturnType =
  resultExpression

// Calling a method that has a parameter list:
methodName(arg, arg)

// Calling a method that has no parameter list:
methodName

Functions as Values

Function values are written (argName: ArgType, ...) => resultExpression:

val double = (num: Int) => num * 2
// double: Int => Int = <function1>

val sum = (a: Int, b: Int) => a + b
sum: (Int, Int) => Int = <function2>

Multi-line functions are written using block expressions:

val printAndDouble = (num: Int) => {
  println("The number was " + num)
  num * 2
}
// printAndDouble: Int => Int = <function1>

scala> printAndDouble(10)
// The number was 10
// res0: Int = 20

We have to write function types when declaring parameters and return types. The syntax is ArgType => ResultType or (ArgType, ...) => ResultType:

def doTwice(value: Int, func: Int => Int): Int =
  func(func(value))
// doTwice: (value: Int, func: Int => Int)Int

doTwice(1, double)
// res0: Int = 4

Function values can be written inline as normal expressions:

doTwice(1, (num: Int) => num * 10)
// res1: Int = 100

We can sometimes omit the argument types, assuming the compiler can figure things out for us:

doTwice(1, num => num * 10)
// res2: Int = 100

Doodle Reference Guide

Imports

// These imports get you everything you need:
import doodle.core._
import doodle.syntax._

Creating Images

// Primitive images (black outline, no fill):
val i: Image = Circle(radius)
val i: Image = Rectangle(width, height)
val i: Image = Triangle(width, height)

// Compound images written using operator syntax:
val i: Image = imageA beside imageB // horizontally adjacent
val i: Image = imageA above  imageB // vertically adjacent
val i: Image = imageA below  imageB // vertically adjacent
val i: Image = imageA on     imageB // superimposed
val i: Image = imageA under  imageB // superimposed

// Compound images written using method call syntax:
val i: Image = imageA.beside(imageB)
// etc...

Styling Images

// Styling images written using operator syntax:
val i: Image = image fillColor color   // new fill color (doesn't change line)
val i: Image = image strokeColor color   // new line color (doesn't change fill)
val i: Image = image strokeWidth integer // new line width (doesn't change fill)
val i: Image = image fillColor color strokeColor otherColor // new fill and line

// Styling images using method call syntax:
val i: Image = imageA.fillColor(color)
val i: Image = imageA.fillColor(color).strokeColor(otherColor)
// etc...

Colours

// Basic colors:
val c: Color = Color.red                       // predefined colors
val c: Color = Color.rgb(255.uByte, 127.uByte, 0.uByte)          // RGB color
val c: Color = Color.rgba(255.uByte, 127.uByte, 0.uByte, 0.5.normalized)    // RGBA color
val c: Color = Color.hsl(15.degrees, 0.25.normalized, 0.5.normalized)       // HSL color
val c: Color = Color.hsla(15.degrees, 0.25.normalized, 0.5.normalized, 0.5.normalized) // HSLA color

// Transforming/mixing colors using operator syntax:
val c: Color = someColor spin       10.degrees     // change hue
val c: Color = someColor lighten    0.1.normalized // change brightness
val c: Color = someColor darken     0.1.normalized // change brightness
val c: Color = someColor saturate   0.1.normalized // change saturation
val c: Color = someColor desaturate 0.1.normalized // change saturation
val c: Color = someColor fadeIn     0.1.normalized // change opacity
val c: Color = someColor fadeOut    0.1.normalized // change opacity

// Transforming/mixing colors using method call syntax:
val c: Color = someColor.spin(10.degrees)
val c: Color = someColor.lighten(0.1.normalized)
// etc...

Paths

// Create path from list of PathElements:
val i: Image = OpenPath(List(
  MoveTo(Vec(0, 0).toPoint),
  LineTo(Vec(10, 10).toPoint)
))

// Create path from other sequence of PathElements:
val i: Image = OpenPath(
  (0 until 360 by 30) map { i =>
    LineTo(Vec.polar(i.degrees, 100).toPoint)
  }
)

// Types of element:
val e1: PathElement = MoveTo(toVec.toPoint)                        // no line
val e2: PathElement = LineTo(toVec.toPoint)                        // straight line
val e3: PathElement = BezierCurveTo(cp1Vec.toPoint, cp2Vec.toPoint, toVec.toPoint) // curved line

// NOTE: If the first element isn't a MoveTo,
//       it is converted to one

Angles and Vecs

val a: Angle = 30.degrees                // angle in degrees
val a: Angle = 1.5.radians               // angle in radians
val a: Angle = math.Pi.radians           // π radians
val a: Angle = 1.turns                   // angle in complete turns

val v: Vec = Vec.zero                    // zero vector (0,0)
val v: Vec = Vec.unitX                   // unit x vector (1,0)
val v: Vec = Vec.unitY                   // unit y vector (0,1)

val v: Vec = Vec(3, 4)                   // vector from cartesian coords
val v: Vec = Vec.polar(30.degrees, 5)    // vector from polar coords
val v: Vec = Vec(2, 1) * 10              // multiply length
val v: Vec = Vec(20, 10) / 10            // divide length
val v: Vec = Vec(2, 1) + Vec(1, 3)       // add vectors
val v: Vec = Vec(5, 5) - Vec(2, 1)       // subtract vectors
val v: Vec = Vec(5, 5) rotate 45.degrees // rotate counterclockwise

val x: Double = Vec(3, 4).x              // x coordinate
val y: Double = Vec(3, 4).y              // y coordinate
val a: Angle  = Vec(3, 4).angle          // counterclockwise from (1, 0)
val l: Double = Vec(3, 4).length         // length