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.

84 lines
2.3 KiB

  1. package nova.monadic_sfx.ui
  2. import scala.concurrent.duration._
  3. import cats.effect.Resource
  4. import io.odin.Logger
  5. import monix.bio.Task
  6. import monix.execution.CancelablePromise
  7. import nova.monadic_sfx.concurrent.Schedulers
  8. import nova.monadic_sfx.ui.DefaultScene
  9. import scalafx.application.JFXApp3
  10. import scalafx.application.JFXApp3.PrimaryStage
  11. import monix.bio.UIO
  12. import monix.eval.Coeval
  13. import scalafx.scene.Scene
  14. import scalafx.scene.Parent
  15. import scalafx.Includes._
  16. import monix.bio.IO
  17. import scalafx.scene.Node
  18. final class FX private (
  19. schedulers: Schedulers,
  20. delegate: JFXApp3,
  21. val await: Task[Unit],
  22. val awaitStop: Task[Unit]
  23. )(implicit logger: Logger[Task]) {
  24. logger.debug("whoopie")
  25. def runOnFx[E, A](io: IO[E, A]) = io.executeOn(schedulers.fx.value)
  26. def addToScene(node: UIO[Node]) =
  27. runOnFx {
  28. for {
  29. p <- node
  30. _ <- UIO(delegate.stage.scene().getChildren += p)
  31. } yield ()
  32. }
  33. }
  34. object FX {
  35. def resource(
  36. schedulers: Schedulers,
  37. stage: Coeval[PrimaryStage],
  38. initialScene: Coeval[Scene] = DefaultScene(),
  39. transitionDelay: FiniteDuration = 500.millis
  40. )(implicit
  41. logger: Logger[Task]
  42. ): Resource[Task, FX] =
  43. Resource
  44. .make(for {
  45. _ <- logger.info("Starting FX App")
  46. makePromise = UIO(CancelablePromise[Unit]())
  47. startSignal <- makePromise
  48. stopSignal <- makePromise
  49. delegate <- Task(new JFXApp3 {
  50. def start(): Unit = {
  51. stage = new PrimaryStage {
  52. scene = initialScene.value()
  53. }
  54. startSignal.success(())
  55. }
  56. override def stopApp(): Unit = {
  57. stopSignal.success(())
  58. }
  59. })
  60. fib <-
  61. Task(delegate.main(Array.empty)).start.executeOn(schedulers.io.value)
  62. fxApp <- Task(
  63. new FX(
  64. schedulers,
  65. delegate,
  66. fib.join,
  67. Task.fromCancelablePromise(stopSignal)
  68. )
  69. )
  70. _ <- Task.fromCancelablePromise(startSignal)
  71. _ <- Task.sleep(transitionDelay)
  72. _ <- Task(delegate.stage = stage.value())
  73. .executeOn(schedulers.fx.value)
  74. .delayExecution(transitionDelay)
  75. } yield fxApp -> fib) { case _ -> fib => fib.cancel }
  76. .map { case a -> _ => a }
  77. }