From 319652b052466d480769a1e6dbbb97390421f483 Mon Sep 17 00:00:00 2001 From: Sarah Gerweck Date: Tue, 14 Apr 2015 23:30:20 -0700 Subject: [PATCH] Basic Scalaz applicative for ScalaFX Observables. --- .../org/gerweck/scalafx/util/package.scala | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/main/scala/org/gerweck/scalafx/util/package.scala diff --git a/src/main/scala/org/gerweck/scalafx/util/package.scala b/src/main/scala/org/gerweck/scalafx/util/package.scala new file mode 100644 index 0000000..b2d65f5 --- /dev/null +++ b/src/main/scala/org/gerweck/scalafx/util/package.scala @@ -0,0 +1,76 @@ +package org.gerweck.scalafx + +import language.implicitConversions + +import scalafx.beans.property._ +import scalafx.beans.value._ +import scalafx.event.subscriptions.Subscription +import scalafx.scene.Node +import scalafx.scene.control._ +import scalafx.scene.layout.GridPane +import scalafx.util.StringConverter + +import scalaz._ +import Scalaz._ + +/** Various implicits and global utilities for ScalaFX work. + * + * @author Sarah Gerweck + */ +package object util { + type Observable[A] = ObservableValue[A, _] + + implicit val observableApplicative = new Applicative[Observable] { + def point[A](a: => A): Observable[A] = { + ObjectProperty[A](a) + } + + def ap[A, B](fa: => Observable[A])(f: => Observable[A => B]): Observable[B] = { + def recalculate: B = (f.value)(fa.value) + + val originalValue = recalculate + + val prop = ObjectProperty[B](originalValue) + + var prevValue = originalValue + + def changeHandler = { + val newVal = recalculate + if (prevValue != newVal) { + prop.value = recalculate + } + } + + fa onChange changeHandler + f onChange changeHandler + + prop + } + } + + implicit class RichProperty[A](val inner: Property[A, _]) extends AnyVal { + def biMap[B <: AnyRef](push: A => B, pull: B => A): ObjectProperty[B] = { + val original = push(inner.value) + val op = ObjectProperty[B](original) + inner onChange { + val oldVal = op.value + val newVal = push(inner.value) + if (oldVal != newVal) { + op.value = push(inner.value) + } + } + op onChange { + val oldVal = inner.value + val newVal = pull(op.value) + if (oldVal != newVal) { + inner.value = newVal + } + } + op + } + } + + implicit class RichGridPane(val inner: GridPane) extends AnyVal { + def addToRow(ri: Int, children: Node*) = inner.addRow(ri, children map {_.delegate}: _*) + } +}