|
|
package nova.monadic_sfx.implicits
import javafx.beans.property.ObjectProperty import javafx.collections.ObservableList import javafx.event.ActionEvent import javafx.event.EventHandler import javafx.scene.{input => jfxsi} import javafx.{event => jfxe} import monix.bio.Task import monix.eval.Coeval import monix.execution.Ack import monix.execution.Cancelable import monix.execution.Scheduler import monix.execution.cancelables.CompositeCancelable import monix.execution.cancelables.SingleAssignCancelable import monix.reactive.Observable import monix.reactive.Observer import monix.reactive.OverflowStrategy import monix.tail.Iterant import monix.{eval => me} import org.gerweck.scalafx.util._ import scalafx.Includes._ import scalafx.beans.property.Property import scalafx.beans.property.ReadOnlyProperty import scalafx.collections.ObservableBuffer import scalafx.event.subscriptions.Subscription import scalafx.scene.Scene import scalafx.scene.control.ButtonBase import scalafx.scene.control.MenuItem import nova.monadic_sfx.util.reactive.store.Sink2
trait JavaFXMonixObservables { import JavaFXMonixObservables._ implicit def extendedScene(scene: Scene) = new SceneExt(scene) implicit def extendedProperty[T, J]( propery: Property[T, J] ): PropertyExt[T, J] = new PropertyExt(propery) implicit def extendedObjectPropety[A](prop: ObjectProperty[A]) = new ObjectPropertyExt[A](prop) implicit def extendedReadOnlyObjectPropety[T, J]( prop: ReadOnlyProperty[T, J] ) = new ReadOnlyPropertyExt[T, J](prop) implicit def extendedObservableList[A]( list: ObservableBuffer[A] ) = new ObservableListExt(list) implicit def extendedStringObservableList( list: ObservableList[String] ) = new StringObservableListExt(list) implicit def extendedObjectPropertyObservableList[A]( prop: ObjectProperty[ObservableList[A]] ) = new ObjectPropertyObservableListExt(prop) implicit def extendedButton(button: ButtonBase) = new ButtonBaseExt(button) implicit def extendedMenuItem(item: MenuItem) = new MenuItemExt(item)
// implicit val implShowForOsRelPath = Show.fromToString[os.Path]
implicit def osRelPath2String(path: os.RelPath): String = path.toString() }
object JavaFXMonixObservables {
final class SceneExt(private val scene: Scene) extends AnyVal {
def observableMousePressed(): Observable[jfxsi.MouseEvent] = { import monix.execution.cancelables.SingleAssignCancelable Observable.create(OverflowStrategy.Unbounded) { sub => val c = SingleAssignCancelable() val l = new jfxe.EventHandler[jfxsi.MouseEvent] { override def handle(event: jfxsi.MouseEvent): Unit = { if (sub.onNext(event) == Ack.Stop) c.cancel() } }
scene.onMousePressed = l c := Cancelable(() => scene.removeEventHandler( jfxsi.MouseEvent.MOUSE_PRESSED, l ) ) c } }
def observableMouseDragged(): Observable[jfxsi.MouseEvent] = { import monix.execution.cancelables.SingleAssignCancelable Observable.create(OverflowStrategy.Unbounded) { sub => val c = SingleAssignCancelable() val l = new jfxe.EventHandler[jfxsi.MouseEvent] { override def handle(event: jfxsi.MouseEvent): Unit = { if (sub.onNext(event) == Ack.Stop) c.cancel() } }
scene.onMouseDragged = l; c := Cancelable(() => scene.removeEventHandler( jfxsi.MouseEvent.MOUSE_DRAGGED, l ) ) c } } }
final class PropertyExt[T, J](private val prop: Property[T, J]) extends AnyVal { // def -->[J1 >: J](sub: Observer[J1]) = {
// prop.onChange((a, b, c) => if (c != null) sub.onNext(c))
// }
def ==>(op: Property[T, J]) = { op <== prop }
def <--( obs: Observable[T] )(implicit s: Scheduler, c: CompositeCancelable): Unit = { c += obs.doOnNextF(v => Coeval(prop.value = v)).subscribe() }
def asOption = prop.map(Option(_))
def observableChange[J1 >: J]: Observable[J1] = { import monix.execution.cancelables.SingleAssignCancelable Observable.create(OverflowStrategy.Unbounded) { sub => val c = SingleAssignCancelable()
val canc = prop.onChange((a, b, c1) => if (c1 != null && sub.onNext(c1) == Ack.Stop) c.cancel() )
c := Cancelable(() => canc.cancel()) c } } }
final class ObjectPropertyExt[A](private val prop: ObjectProperty[A]) extends AnyVal {
// def -->(sub: Observer[A]) =
// prop.onChange((a, b, c) =>
// if (c != null)
// if (sub.onNext(c) == Ack.Stop) throw new Exception("boom")
// )
def -->(sink: Sink2[A])(implicit s: Scheduler, c: CompositeCancelable) = c += observableChange.doOnNextF(sink.offer).subscribe()
def ==>(op: Property[A, A])(implicit c: CompositeCancelable) = { val canc = prop.onChange((a, b, c) => if (c != null) op() = c) c += Cancelable(() => canc.cancel()) }
def <--( obs: Observable[A] )(implicit s: Scheduler, c: CompositeCancelable) = { c += obs.doOnNextF(v => Coeval(prop() = v)).subscribe() }
def observableChange[J1 >: A]: Observable[J1] = { import monix.execution.cancelables.SingleAssignCancelable Observable.create(OverflowStrategy.Unbounded) { sub => val c = SingleAssignCancelable()
val canc = prop.onChange((_, _, c1) => if (c1 != null && sub.onNext(c1) == Ack.Stop) c.cancel() )
c := Cancelable(() => canc.cancel()) c } } }
final class ObservableListExt[A](private val buffer: ObservableBuffer[A]) extends AnyVal {
// def -->(sub: Observer[A]) =
// buffer.onChange((a, b, c) => if (c != null) sub.onNext(c))
// def -->(op: Property[A, A]) = {
// buffer.onChange((a, b, c) => if (c != null) op() = c)
// }
def <--( obs: Observable[A] )(implicit s: Scheduler, c: CompositeCancelable) = { c += obs .doOnNextF(v => for { _ <- Coeval(buffer.clear()) _ <- Coeval(buffer += v) } yield () ) .subscribe() }
// def observableChange[J1 >: A]: Observable[J1] = {
// import monix.execution.cancelables.SingleAssignCancelable
// Observable.create(OverflowStrategy.Unbounded) { sub =>
// val c = SingleAssignCancelable()
// implicit val s = sub.scheduler
// val canc =
// buffer.onChange((buf, _) =>
// loop(sub, buf.toIterable.iterator, c).runToFuture
// )
// c := Cancelable(() => canc.cancel())
// c
// }
// }
// private def loop(
// sub: Observer[A],
// it: Iterator[A],
// c: Cancelable
// ): Task[Unit] =
// if (it.hasNext) {
// val next = it.next()
// Task.deferFuture(sub.onNext(next)).flatMap {
// case Ack.Continue => loop(sub, it, c)
// case Ack.Stop => Task(c.cancel())
// }
// } else Task.unit
}
final class StringObservableListExt( private val buffer: ObservableList[String] ) extends AnyVal { // def ++=[T](that: Seq[T])(implicit S: Show[T]): Unit =
// buffer ++= that.map(S.show)
// def ++=[T](that: Seq[T])(implicit C: CssPath[T]): Unit =
// buffer ++= that.map(C.path)
}
final class ReadOnlyPropertyExt[T, J]( private val prop: ReadOnlyProperty[T, J] ) extends AnyVal { // def -->[J1 >: J](sub: Observer[J1]) = {
// prop.onChange((a, b, c) => if (c != null) sub.onNext(c))
// }
def ==>(op: Property[T, J]) = { op <== prop }
def observableChange[J1 >: J]: Observable[J1] = { import monix.execution.cancelables.SingleAssignCancelable Observable.create(OverflowStrategy.Unbounded) { sub => val c = SingleAssignCancelable()
val canc = prop.onChange((a, b, c1) => if (c1 != null && sub.onNext(c1) == Ack.Stop) c.cancel() )
c := Cancelable(() => canc.cancel()) c } } }
final class ObjectPropertyObservableListExt[A]( private val prop: ObjectProperty[ObservableList[A]] ) extends AnyVal {
def <--( obs: Observable[Seq[A]] )(implicit s: Scheduler, c: CompositeCancelable) = { c += obs .doOnNext(v => me.Task(prop() = ObservableBuffer.from(v))) .subscribe() }
// def -->(sub: Observer[A])(implicit s: Scheduler) = {
// val c = SingleAssignCancelable()
// val subs: Subscription = prop.onChange((a, b, c1) =>
// if (c1 != null)
// Iterant[Task]
// .fromIterable(c1.toIterable)
// .consume
// .use(consume(sub, c, _))
// .runToFuture
// )
// c := Cancelable(() => subs.cancel())
// }
// private def loop(sub: Observer[A], it: Iterator[A]): Task[Unit] =
// if (it.hasNext) {
// val next = it.next()
// Task.deferFuture(sub.onNext(next)).flatMap {
// case Ack.Continue => loop(sub, it)
// case Ack.Stop => Task.unit
// }
// } else Task.unit
// private def consume(
// sub: Observer[A],
// c: Cancelable,
// consumer: Iterant.Consumer[Task, A]
// ): Task[Unit] =
// consumer.pull.flatMap {
// case Left(value) => Task.unit
// case Right(value) =>
// Task.deferFuture(sub.onNext(value)).flatMap {
// case Ack.Continue => consume(sub, c, consumer)
// case Ack.Stop => Task(c.cancel())
// }
// }
}
final class ObjectPropertyActionEvent( private val prop: ObjectProperty[EventHandler[ActionEvent]] ) extends AnyVal { // def <--(obs: Observable[ActionEvent])(implicit s: Scheduler) = {
// obs.doOnNext(v => me.Task(prop() = ObservableBuffer.from(v))).subscribe()
// }
// def -->(sub: Observer[ActionEvent]) =
// prop().
}
// def emit(prop: ObjectProperty[EventHandler[ActionEvent]]) =
final class ButtonBaseExt( private val button: ButtonBase ) extends AnyVal {
def observableAction: Observable[jfxe.ActionEvent] = { import monix.execution.cancelables.SingleAssignCancelable Observable.create(OverflowStrategy.Unbounded) { sub => val c = SingleAssignCancelable() val l = new jfxe.EventHandler[jfxe.ActionEvent] { override def handle(event: jfxe.ActionEvent): Unit = { if (sub.onNext(event) == Ack.Stop) c.cancel() } }
button.onAction = l c := Cancelable(() => button.removeEventHandler( jfxe.ActionEvent.ACTION, l ) ) c } } }
final class MenuItemExt( private val item: MenuItem ) extends AnyVal {
def observableAction: Observable[jfxe.ActionEvent] = { import monix.execution.cancelables.SingleAssignCancelable Observable.create(OverflowStrategy.Unbounded) { sub => val c = SingleAssignCancelable() val l = new jfxe.EventHandler[jfxe.ActionEvent] { override def handle(event: jfxe.ActionEvent): Unit = { if (sub.onNext(event) == Ack.Stop) c.cancel() } }
item.onAction = l c := Cancelable(() => item.removeEventHandler( jfxe.ActionEvent.ACTION, l ) ) c } } } }
|