package wow.doge.mygame.launcher import scala.concurrent.duration.FiniteDuration import scala.concurrent.duration._ import cats.effect.concurrent.Deferred import javafx.application.Platform import monix.bio.Task import monix.catnap.CancelableF import monix.eval.{Task => ETask} import monix.reactive.Observable import scalafx.Includes._ import scalafx.application.JFXApp import scalafx.application.JFXApp.PrimaryStage import scalafx.scene.control.Button import scalafx.stage.StageStyle import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.implicits.JavaFXMonixObservables._ import wow.doge.mygame.utils.IOUtils._ object Launcher { sealed trait LauncherResult object LauncherResult { case object LaunchGame extends LauncherResult case object Exit extends LauncherResult } class Props( val schedulers: Schedulers, val signal: Deferred[Task, LauncherResult] ) { val create = Task(new Launcher(this)) } } class Launcher private (props: Launcher.Props) { import Launcher._ private lazy val launchButton = new Button { text = "Launch" } private lazy val launchAction = launchButton .observableAction() .doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame))) private lazy val exitButton = new Button { text = "Exit" } private lazy val exitAction = exitButton .observableAction() .doOnNext(_ => toTask(props.signal.complete(LauncherResult.Exit))) private lazy val _scene = DefaultUI.scene(launchButton, exitButton) private lazy val _stage = new PrimaryStage { scene = _scene } private lazy val internal = new JFXApp { stage = _stage stage.initStyle(StageStyle.Undecorated) // ResizeHelper.addResizeListener(stage) } private lazy val sceneDragObservable = { lazy val mpo = _scene.observableMousePressed() lazy val mdo = _scene.observableMouseDragged() mpo.mergeMap(pressEvent => mdo.doOnNext(dragEvent => ETask( _stage.setX(dragEvent.screenX - pressEvent.sceneX) ) >> ETask( _stage.setY( dragEvent.screenY - pressEvent.sceneY ) ) ) ) } def init(delay: FiniteDuration = 2000.millis) = for { _ <- Task(Platform.setImplicitExit(false)) fib <- Task(internal.main(Array.empty)).start _ <- Task.sleep(500.millis) sceneDragFib <- toIO(sceneDragObservable.completedL).start fib2 <- toIO( Observable(launchAction, exitAction).merge .doOnNext(_ => ETask(internal.stage.close()).executeOn(props.schedulers.fx) ) .completedL ).start c <- CancelableF[Task](fib.cancel >> fib2.cancel >> sceneDragFib.cancel) } yield (c) }