Skip to content

Instantly share code, notes, and snippets.

@momania
Created March 31, 2011 09:01
Show Gist options
  • Save momania/896062 to your computer and use it in GitHub Desktop.
Save momania/896062 to your computer and use it in GitHub Desktop.
Over engineered Akka FSM scala Swing undecorated dialog using shapes and fading (why? because we can!)
package notification
import com.sun.awt.AWTUtilities
import java.awt.geom.RoundRectangle2D
import org.jdesktop.animation.timing.{TimingTarget, Animator}
import swing._
import event.MouseClicked
import com.efgfp.creditspy.util.GuiUtil
import akka.actor.{FSM, Actor}
import org.jdesktop.animation.timing.Animator.{Direction, RepeatBehavior}
import swing.RichWindow.Undecorated
sealed trait DialogState
case object Hidden extends DialogState
case object Visible extends DialogState
case object Opening extends DialogState
case object Closing extends DialogState
sealed trait DialogAction
case object ShowDialog extends DialogAction
case object CloseDialog extends DialogState
private trait InternalNotification
private case object Opened extends InternalNotification
private case object Closed extends InternalNotification
class NotificationDialog(contentsComponent: Component) extends Actor with FSM[DialogState, Unit] with TimingTarget {
outer =>
/**
* Dialog showing the component
*/
val dialog = new Dialog with Undecorated {
peer.setAlwaysOnTop(true)
size = contentsComponent.preferredSize
location = GuiUtil.calculateLocationPoint(size)
contents = contentsComponent
val shape = new RoundRectangle2D.Double(0, 0, size.getWidth, size.getHeight, 15d, 15d)
AWTUtilities.setWindowShape(peer, shape)
listenTo(contentsComponent.mouse.clicks)
reactions += {
case MouseClicked(_, _, _, _, _) =>
outer.self ! CloseDialog
}
}
/**
* Animator for the fading in and out
*/
val animator = new Animator(600, 1d, RepeatBehavior.LOOP, this)
/**
* FSM states
*/
when(Hidden) {
case Ev(ShowDialog) =>
openDialog
goto(Opening)
}
when(Opening) {
case Ev(Opened) =>
goto(Visible)
case Ev(CloseDialog) =>
closeDialog
goto(Closing)
}
when(Visible) {
case Ev(CloseDialog) =>
closeDialog
goto(Closing)
}
when(Closing) {
case Ev(Closed) =>
stop
}
whenUnhandled{
case unhandled =>
stay
}
onTermination{
case StopEvent(_, _, _) =>
dialog.close
dialog.dispose
}
startWith(Hidden, ())
initialize
/**
* Fading dialog in and out
*/
private def openDialog() = {
AWTUtilities.setWindowOpacity(dialog.peer, 0f)
dialog.open
animator.setStartFraction(0.0f)
animator.setStartDirection(Direction.FORWARD)
animator.start
}
private def closeDialog() = {
if (animator.isRunning) {
animator.stop
}
animator.setStartFraction(1.0f)
AWTUtilities.setWindowOpacity(dialog.peer, 1.0f)
animator.setStartDirection(Direction.BACKWARD)
animator.start
}
/**
* Timer event methods
*/
def timingEvent(fraction: Float) = {
AWTUtilities.setWindowOpacity(dialog.peer, fraction)
}
def end() = {
animator.getStartDirection match {
case Direction.BACKWARD => self ! Closed
case Direction.FORWARD => self ! Opened
}
}
def repeat() = {}
def begin() = {}
}
import akka.actor.Actor
import swing.Label
import java.util.concurrent.TimeUnit
import org.multiverse.api.latches.StandardLatch
import java.awt.Dimension
object NotificationApp extends Application {
val helloLabel = new Label {
text = "Hello FSM Dialog!"
preferredSize = new Dimension(300, 100)
}
val closedLatch = new StandardLatch
val notificationDialog = Actor.actorOf(new NotificationDialog(helloLabel) {
onTransition { (from, to) => if (to == Closed) closedLatch.open }
}).start
notificationDialog ! ShowDialog
TimeUnit.SECONDS.sleep(4)
notificationDialog ! CloseDialog
closedLatch.tryAwait(2, TimeUnit.SECONDS)
exit(0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment