In software development there are no silver bullets, but I am always looking out for the next bronze one.

Saturday, December 22, 2007

GUI Building with Scala - Part 3 (SQUIB and Scene Graphs)

    

I have opted to rename this little project from the rather generic, "Scala Gui Builder" to SQUIB (Scala's Quirky User Interface Builder). Originally, I was going to demonstrate little custom components I had developed to be used by SQUIB to draw shapes, but when I saw the announcement of the Java Scene Graph library (https://scenegraph.dev.java.net/), it was clear that it a perfect fit for SQUIB.


    

I have just started development of Scene Graph support for SQUIB, so only minimal features are supported. Additionally, the Scene Graphs APIs are not finalized yet, so it would be not feasible to try to create a complete library against a changing API.


A Simple Example


I have created example programs to demonstrate the potential for Scene Graphs in SQUIB. Requirements for SQUIB with Scene Graph support are the updated SQUIB jar file
and the Scene Graph jar file. Here
is a link to the source for the first example or you could copy and paste from below. Compile and run:

C:\tmp>scalac -cp ScalaSquibV0_3.jar;Scenario-0.4.jar SceneGraphSimple.scala

C:\tmp\scala -cp .;ScalaSquibV0_3.jar;Scenario-0.4.jar tfd.scala.squib.scenegraph.demo.SceneGraphSimple

Source Code:



package tfd.scala.squib.scenegraph.demo;

import java.awt.{Color, Point, Font, Dimension, Rectangle, BasicStroke}
import javax.swing.{JFrame}

import com.sun.scenario.scenegraph._
import com.sun.scenario.animation._

import tfd.scala.squib._
import tfd.scala.squib.scenegraph._

object SceneGraphSimple extends Application {
text.attributesDefault = attributes(
'font -> new Font("Courier", Font.BOLD, 24),
'mode -> SGAbstractShape.Mode.FILL,
'fillPaint -> Color.BLUE
)

val frm = frame(
attributes(
'title->"SQUIB Scenegraph Demo",
'visible -> true,
'defaultCloseOperation -> JFrame.EXIT_ON_CLOSE,
'size -> new Dimension(100,200)
),
borderlayout(),
contents(
scenepanel("scene",
'scene -> group("root",
group("sub",
translate(50, 100,
rotate("square", 0.0,
shape(
'shape -> new Rectangle(-20,-20,40,40),
'mode -> SGAbstractShape.Mode.STROKE_FILL,
'fillPaint -> Color.RED,
'drawPaint -> Color.ORANGE,
'drawStroke -> new BasicStroke(5.0f)
)
)
),
scale("blah", 1.0, 1.0,
text("blah",
'text -> "Blah",
'location -> new Point(10,20)
)
),
translate(10, 110,
composite(0.75,
component('component -> button("FooBar"))
)
)
)
),
'background -> Color.GREEN
) -> "Center"
)
)

Clip.create(
500,
600.0,
rotate.id("square"),
"rotation",
Array(-3.14159f, 3.14159f).map(_.asInstanceOf[Object])
).start();

Clip.create(
500,
900.0,
scale.id("blah"),
"scaleY",
Array(0.5f, 5.0f).map(_.asInstanceOf[Object])
).start();
}

Screenshot of Simple Example:



The Array(0.5f, 5.0f).map(_.asInstanceOf[Object]) expression represents one of the few areas where Scala/Java integration is not seamless. Scala does not handle Java variable arguments and "sees" the signature of the method as requiring an Array. The Scala code needs to explicitly put those parameters into an Array. Perhaps this could be done by an implicit conversion ? I'll have to experiment sometime.


A Spinning Calculator?


This is a little more elaborate example that embeds the calculator from a previous
post in a scene graph. Source is available here
. Compile and run:

C:\tmp>scalac -cp ScalaSquibV0_3.jar;Scenario-0.4.jar RotatingCalculator.scala

C:\tmp\scala -cp .;ScalaSquibV0_3.jar;Scenario-0.4.jar tfd.scala.squib.scenegraph.demo.RotatingCalculator

Screenshot of Rotating Calculator:



Looking at the RotatingCalculator source, you will see new button factory methods that allow definition of Actions in the button declaration itself and other "shorthand" methods. I am still planning to get the source out on Google Code in the coming months.


The examples here show the power of the Scene Graph library and how SQUIB can be used to generate scene graphs in Scala in a rather expressive manner.