package wow.doge.mygame.launcher import cats.effect.Resource import cats.effect.concurrent.Deferred import cats.kernel.Eq import javafx.application.Platform import monix.bio.Task import monix.bio.UIO import monix.catnap.CancelableF import monix.execution.CancelablePromise import monix.reactive.Observable import monix.{eval => me} 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.FxScheduler 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 implicit val eqForLR = Eq.fromUniversalEquals[LauncherResult] } class Props( // val schedulers: Schedulers, val fxScheduler: FxScheduler, val signal: Deferred[Task, LauncherResult] ) { val create = UIO(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 def internal(startSignal: CancelablePromise[Unit]) = new JFXApp { stage = _stage stage.initStyle(StageStyle.Undecorated) // ResizeHelper.addResizeListener(stage) startSignal.success(()) } private lazy val sceneDragObservable = { val mpo = _scene.observableMousePressed() val mdo = _scene.observableMouseDragged() mpo.concatMap(pressEvent => mdo.doOnNext(dragEvent => me.Task(pprint.log("emitted")) >> me.Task( _stage.setX(dragEvent.screenX - pressEvent.sceneX) ) >> me.Task( _stage.setY( dragEvent.screenY - pressEvent.sceneY ) ) ) ) } def init = Resource.make(for { _ <- Task(Platform.setImplicitExit(false)) startSignal <- Task(CancelablePromise[Unit]()) delegate <- Task(internal(startSignal)) combinedFib <- Task .parZip2( Task(delegate.main(Array.empty)), Task.fromCancelablePromise(startSignal) >> toIO( me.Task.parSequence( List( sceneDragObservable.completedL, Observable(launchAction, exitAction).merge .doOnNext(_ => me.Task(delegate.stage.close()) .executeOn(props.fxScheduler.value) ) .completedL ) ) ) ) .start _ <- Task.fromCancelablePromise(startSignal) c <- CancelableF[Task](combinedFib.cancel) } yield c)(_.cancel) }