You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.0 KiB

  1. package nova.monadic_sfx.implicits
  2. import javafx.beans.property.ObjectProperty
  3. import javafx.collections.ObservableList
  4. import javafx.scene.{input => jfxsi}
  5. import javafx.{event => jfxe}
  6. import monix.bio.Task
  7. import monix.execution.Ack
  8. import monix.execution.Cancelable
  9. import monix.execution.Scheduler
  10. import monix.reactive.Observable
  11. import monix.reactive.Observer
  12. import monix.reactive.OverflowStrategy
  13. import monix.tail.Iterant
  14. import monix.{eval => me}
  15. import scalafx.Includes._
  16. import scalafx.beans.property.Property
  17. import scalafx.beans.value.ObservableValue
  18. import scalafx.collections.ObservableBuffer
  19. import scalafx.scene.Scene
  20. import scalafx.scene.control.ButtonBase
  21. object JavaFXMonixObservables {
  22. implicit final class SceneObservables(private val scene: Scene)
  23. extends AnyVal {
  24. def observableMousePressed(): Observable[jfxsi.MouseEvent] = {
  25. import monix.execution.cancelables.SingleAssignCancelable
  26. Observable.create(OverflowStrategy.Unbounded) { sub =>
  27. val c = SingleAssignCancelable()
  28. val l = new jfxe.EventHandler[jfxsi.MouseEvent] {
  29. override def handle(event: jfxsi.MouseEvent): Unit = {
  30. if (sub.onNext(event) == Ack.Stop) c.cancel()
  31. }
  32. }
  33. scene.onMousePressed = l
  34. c := Cancelable(() =>
  35. scene.removeEventHandler(
  36. jfxsi.MouseEvent.MOUSE_PRESSED,
  37. l
  38. )
  39. )
  40. c
  41. }
  42. }
  43. def observableMouseDragged(): Observable[jfxsi.MouseEvent] = {
  44. import monix.execution.cancelables.SingleAssignCancelable
  45. Observable.create(OverflowStrategy.Unbounded) { sub =>
  46. val c = SingleAssignCancelable()
  47. val l = new jfxe.EventHandler[jfxsi.MouseEvent] {
  48. override def handle(event: jfxsi.MouseEvent): Unit = {
  49. if (sub.onNext(event) == Ack.Stop) c.cancel()
  50. }
  51. }
  52. scene.onMouseDragged = l
  53. c := Cancelable(() =>
  54. scene.removeEventHandler(
  55. jfxsi.MouseEvent.MOUSE_DRAGGED,
  56. l
  57. )
  58. )
  59. c
  60. }
  61. }
  62. }
  63. // implicit final class BindObs[T, J](private val prop: Property[T, J])
  64. // extends AnyVal {
  65. // def -->(op: Observer[T]) = {
  66. // op.onNext(prop.value)
  67. // }
  68. // def <--(obs: Observable[T])(implicit s: Scheduler) = {
  69. // obs.doOnNext(v => me.Task(prop.value = v)).subscribe()
  70. // }
  71. // def observableChange[J1 >: J]()
  72. // : Observable[(ObservableValue[T, J], J1, J1)] = {
  73. // import monix.execution.cancelables.SingleAssignCancelable
  74. // Observable.create(OverflowStrategy.Unbounded) { sub =>
  75. // val c = SingleAssignCancelable()
  76. // val canc = prop.onChange((a, b, c) => sub.onNext((a, b, c)))
  77. // c := Cancelable(() => canc.cancel())
  78. // c
  79. // }
  80. // }
  81. // }
  82. implicit final class BindObs2[A](private val prop: ObjectProperty[A])
  83. extends AnyVal {
  84. // def -->(sub: Var[A]) =
  85. // prop.onChange((a, b, c) => sub := c)
  86. def -->(sub: Observer[A]) =
  87. prop.onChange((a, b, c) => if (c != null) sub.onNext(c))
  88. // def -->[J1 >: A, T](
  89. // op: Observable[J1] => me.Task[T]
  90. // )(implicit s: Scheduler) = {
  91. // op(prop.observableChange().map(_._3)).runToFuture
  92. // }
  93. def <--(obs: Observable[A])(implicit s: Scheduler) = {
  94. obs.doOnNext(v => me.Task(prop() = v)).subscribe()
  95. }
  96. def observableChange[J1 >: A]()
  97. : Observable[(ObservableValue[A, A], J1, J1)] = {
  98. import monix.execution.cancelables.SingleAssignCancelable
  99. Observable.create(OverflowStrategy.Unbounded) { sub =>
  100. val c = SingleAssignCancelable()
  101. val canc = prop.onChange((a, b, c) => sub.onNext((a, b, c)))
  102. c := Cancelable(() => canc.cancel())
  103. c
  104. }
  105. }
  106. }
  107. implicit final class ObjectPropertyObservableListExt[A](
  108. private val prop: ObjectProperty[ObservableList[A]]
  109. ) extends AnyVal {
  110. def <--(obs: Observable[Seq[A]])(implicit s: Scheduler) = {
  111. obs.doOnNext(v => me.Task(prop() = ObservableBuffer.from(v))).subscribe()
  112. }
  113. def -->(sub: Observer[A])(implicit s: Scheduler) =
  114. prop.onChange((a, b, c) =>
  115. if (c != null)
  116. Iterant[Task]
  117. .fromIterable(c.toIterable)
  118. .consume
  119. .use(consume(sub, _))
  120. .runToFuture
  121. )
  122. private def loop(sub: Observer[A], it: Iterator[A]): Task[Unit] =
  123. if (it.hasNext) {
  124. val next = it.next()
  125. Task.deferFuture(sub.onNext(next)).flatMap {
  126. case Ack.Continue => loop(sub, it)
  127. case Ack.Stop => Task.unit
  128. }
  129. } else Task.unit
  130. private def consume(
  131. sub: Observer[A],
  132. consumer: Iterant.Consumer[Task, A]
  133. ): Task[Unit] =
  134. consumer.pull.flatMap {
  135. case Left(value) => Task.unit
  136. case Right(value) =>
  137. Task.deferFuture(sub.onNext(value)).flatMap {
  138. case Ack.Continue => consume(sub, consumer)
  139. case Ack.Stop => Task.unit
  140. }
  141. }
  142. }
  143. implicit final class OnActionObservable(
  144. private val button: ButtonBase
  145. ) extends AnyVal {
  146. // def -->[T](
  147. // op: Observable[jfxe.ActionEvent] => me.Task[T]
  148. // )(implicit s: Scheduler) = {
  149. // op(button.observableAction()).runToFuture
  150. // }
  151. // def -->(
  152. // sub: ConcurrentSubject[jfxe.ActionEvent, jfxe.ActionEvent]
  153. // ) = {
  154. // button.onAction = value => sub.onNext(value)
  155. // }
  156. def observableAction(): Observable[jfxe.ActionEvent] = {
  157. import monix.execution.cancelables.SingleAssignCancelable
  158. Observable.create(OverflowStrategy.Unbounded) { sub =>
  159. val c = SingleAssignCancelable()
  160. val l = new jfxe.EventHandler[jfxe.ActionEvent] {
  161. override def handle(event: jfxe.ActionEvent): Unit = {
  162. if (sub.onNext(event) == Ack.Stop) c.cancel()
  163. }
  164. }
  165. button.onAction = l
  166. c := Cancelable(() =>
  167. button.removeEventHandler(
  168. jfxe.ActionEvent.ACTION,
  169. l
  170. )
  171. )
  172. c
  173. }
  174. }
  175. }
  176. }