From fa7419d101ce6fe9f96f7b1f4582f64b82d9c516 Mon Sep 17 00:00:00 2001 From: Sarah Gerweck Date: Mon, 4 May 2015 11:44:46 -0700 Subject: [PATCH] Base version of `observe` method on tuples. This commit also includes an `observe2`, which operates directly on a tuple without explicitly converting to an HList. I'm committing it for posterity, but the next commit will remove it because it doesn't give a narrow enough output type. --- .../org/gerweck/scalafx/util/observable.scala | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/main/scala/org/gerweck/scalafx/util/observable.scala b/src/main/scala/org/gerweck/scalafx/util/observable.scala index 3a961b9..92555de 100644 --- a/src/main/scala/org/gerweck/scalafx/util/observable.scala +++ b/src/main/scala/org/gerweck/scalafx/util/observable.scala @@ -54,6 +54,63 @@ trait ObservableImplicits { implicit def enrichObservable[A, B](o: ObservableValue[A, B]) = new RichObservable(o) implicit def enrichProperty[A, B](o: Property[A, B]) = new RichProperty(o) + implicit def enrichTuple[A <: Product](a: A) = new RichTuple(a) +} + +class RichTuple[A <: Product](val self: A) extends AnyVal { + import shapeless._ + import shapeless.syntax._ + import shapeless.ops.hlist._ + + /* It's possible to do this operation without conversion directly using + * Shapeless's `tuple` package, but it can't infer the exact output type, + * which is far less useful. + */ + def observe + [L <: HList, Unwrapped <: HList, Tupled <: Product] + (implicit tohl: Generic.Aux[A, L], + lister: ToTraversable.Aux[L, List, Observable[_]], + uw: Mapper.Aux[ObservableUnwrapper.type, L, Unwrapped], + tplr: Tupler.Aux[Unwrapped, Tupled]): ObservableValue[Tupled, Tupled] = { + val asHList: L = tohl.to(self) + def calculate(): Tupled = uw(asHList).tupled + + val original = calculate() + val prop = ObjectProperty[Tupled](original) + + for { + component <- asHList.to[List] + } { + component onChange { + prop.value = calculate() + } + } + prop + } + + import shapeless.ops.tuple.{ ToTraversable, Mapper } + import shapeless.syntax.std.tuple._ + + def observe2[Unwrapped <: Product] + (implicit lister: ToTraversable.Aux[A, List, Observable[_]], + uw: Mapper.Aux[A, ObservableUnwrapper.type, Unwrapped]): + ObservableValue[Unwrapped, Unwrapped] = { + def calculate(): Unwrapped = self.map(ObservableUnwrapper) + + val original = calculate() + val prop = ObjectProperty[Unwrapped](original) + + for { + component <- self.to[List] + } { + component onChange { + prop.value = calculate() + } + } + prop + } + + // def omap[B] } class RichObservable[A, C](val self: ObservableValue[A, C]) extends AnyVal {