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.
235 lines
7.5 KiB
235 lines
7.5 KiB
package nova.monadic_sfx
|
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
import scala.util.Random
|
|
|
|
import com.jfoenix.controls.JFXDialog
|
|
import com.softwaremill.macwire._
|
|
import io.odin.Logger
|
|
import monix.bio.IO
|
|
import monix.bio.Task
|
|
import monix.eval.Coeval
|
|
import monix.{eval => me}
|
|
import nova.monadic_sfx.executors.Schedulers
|
|
import nova.monadic_sfx.implicits._
|
|
import nova.monadic_sfx.ui.MyFxApp
|
|
import nova.monadic_sfx.ui.components.router.FXRouter
|
|
import nova.monadic_sfx.ui.components.router.Page
|
|
import nova.monadic_sfx.ui.components.todo.TodoListStore
|
|
import nova.monadic_sfx.ui.components.todo.TodoListView
|
|
import nova.monadic_sfx.util.MutHistory
|
|
import nova.monadic_sfx.util.controls.JFXButton
|
|
import org.gerweck.scalafx.util._
|
|
import org.kordamp.bootstrapfx.BootstrapFX
|
|
import scalafx.Includes._
|
|
import scalafx.application.JFXApp.PrimaryStage
|
|
import scalafx.beans.property.ObjectProperty
|
|
import scalafx.beans.property.StringProperty
|
|
import scalafx.collections.ObservableBuffer
|
|
import scalafx.geometry.Insets
|
|
import scalafx.geometry.Pos
|
|
import scalafx.scene.Parent
|
|
import scalafx.scene.Scene
|
|
import scalafx.scene.control.Label
|
|
import scalafx.scene.control.TableColumn
|
|
import scalafx.scene.control.TableView
|
|
import scalafx.scene.layout.BorderPane
|
|
import scalafx.scene.layout.HBox
|
|
import scalafx.scene.layout.Priority
|
|
import scalafx.scene.layout.StackPane
|
|
|
|
class MainApp(
|
|
// spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
|
schedulers: Schedulers,
|
|
startTime: Long
|
|
)(implicit logger: Logger[Task]) {
|
|
|
|
private lazy val _scene = new Scene {
|
|
root = new HBox {
|
|
padding = Insets(20)
|
|
// style = """| -fx-background-color: rgb(38, 38, 38);
|
|
// | -fx-text-fill: white;""".stripMargin
|
|
stylesheets ++= Seq(
|
|
BootstrapFX.bootstrapFXStylesheet,
|
|
os.rel / "static" / "css" / "main.css"
|
|
)
|
|
}
|
|
}
|
|
|
|
private lazy val stage = new PrimaryStage {
|
|
title = "Simple ScalaFX App"
|
|
scene = _scene
|
|
width = 640
|
|
height = 480
|
|
// resizable = false
|
|
}
|
|
|
|
val program = for {
|
|
(fxApp, fxAppFib) <- wire[MyFxApp].init(stage)
|
|
_ <-
|
|
wire[MainAppDelegate].init
|
|
.flatMap(mainSceneNode => Task(_scene.getChildren += mainSceneNode))
|
|
.executeOn(schedulers.fx)
|
|
_ <- Task(stage.resizable = false).executeOn(schedulers.fx)
|
|
currentTime <- IO.clock.realTime(TimeUnit.MILLISECONDS)
|
|
_ <- logger.info(
|
|
s"Application started in ${(currentTime - startTime) / 1000f} seconds"
|
|
)
|
|
// _ <- Task(CSSFX.start(stage))
|
|
_ <- fxAppFib.join
|
|
} yield ()
|
|
|
|
}
|
|
|
|
class MainAppDelegate(schedulers: Schedulers)(implicit logger: Logger[Task]) {
|
|
val buttonStyle = """| -fx-padding: 0.7em 0.57em;
|
|
| -fx-font-size: 14px;
|
|
| -jfx-button-type: RAISED;
|
|
| -fx-background-color: rgb(77,102,204);
|
|
| -fx-pref-width: 200;
|
|
| -fx-text-fill: WHITE; """.stripMargin
|
|
|
|
val init =
|
|
for {
|
|
//FXRouter does not allocate mutable state so it's ok to use pure here
|
|
history <- Task(new MutHistory[Page](Page.Home))
|
|
router <- Task.pure(new FXRouter[Page](history))
|
|
routerStore <- router.store(Page.Home, logger)
|
|
todoStore <- TodoListStore(logger)
|
|
todoComponent <- TodoListView(todoStore)
|
|
resolver: PartialFunction[Page, Task[Parent]] = {
|
|
case Page.Home =>
|
|
Task(new Label {
|
|
styleClass ++= Seq("text-white")
|
|
text = "HomePage"
|
|
})
|
|
case Page.UserHome(id0) =>
|
|
Task(new Label {
|
|
styleClass ++= Seq("text-white")
|
|
text = s"User Home, Id = $id0"
|
|
})
|
|
case Page.Todo =>
|
|
Task.pure(todoComponent)
|
|
}
|
|
routerNode <-
|
|
Task
|
|
.deferAction(implicit s =>
|
|
Task(new HBox {
|
|
alignment = Pos.Center
|
|
//TODO find a better way to do this
|
|
var oldValue: Option[Parent] = None
|
|
children <-- router
|
|
.render(resolver)(routerStore)
|
|
// .scanEvalF[Coeval, (Option[Parent], Option[Parent])](
|
|
// Coeval.pure(None -> None)
|
|
// ) {
|
|
// case (oldValue, newValue) => Coeval(None -> None)
|
|
// }
|
|
// call cancel on the old component to cancel all subscriptions
|
|
.doOnNextF(newValue =>
|
|
Coeval { oldValue.foreach(_ => ()) } >> Coeval {
|
|
oldValue = Some(newValue)
|
|
}
|
|
)
|
|
.map(_.delegate)
|
|
})
|
|
)
|
|
|
|
mainSceneNode <- Task.deferAction(implicit s =>
|
|
Task(new StackPane { root =>
|
|
hgrow = Priority.Always
|
|
vgrow = Priority.Always
|
|
children = new BorderPane {
|
|
hgrow = Priority.Always
|
|
vgrow = Priority.Always
|
|
center = routerNode
|
|
bottom = new HBox {
|
|
alignment = Pos.Center
|
|
spacing = 20
|
|
children = Seq(
|
|
new JFXButton {
|
|
text = "Forward"
|
|
style = buttonStyle
|
|
onAction = () => {
|
|
history.forward()
|
|
routerStore.onNext(FXRouter.HistoryEvent(history.current))
|
|
}
|
|
},
|
|
new JFXButton {
|
|
text = "Backward"
|
|
style = buttonStyle
|
|
onAction = () => {
|
|
history.backward()
|
|
routerStore.onNext(FXRouter.HistoryEvent(history.current))
|
|
}
|
|
},
|
|
new JFXButton {
|
|
text = "Home"
|
|
style = buttonStyle
|
|
obsAction
|
|
.useLazyEval(
|
|
me.Task.pure(FXRouter.Replace(Page.Home))
|
|
) --> routerStore
|
|
},
|
|
new JFXButton {
|
|
text = "Todo"
|
|
style = buttonStyle
|
|
obsAction
|
|
.useLazyEval(
|
|
me.Task.pure(FXRouter.Replace(Page.Todo))
|
|
) --> routerStore
|
|
},
|
|
new JFXButton {
|
|
text = "UserHome"
|
|
style = buttonStyle
|
|
obsAction
|
|
.useLazyEval(
|
|
me.Task(
|
|
FXRouter.Replace(Page.UserHome(Random.nextInt(20)))
|
|
)
|
|
) --> routerStore
|
|
},
|
|
new JFXButton {
|
|
text = "Dialog"
|
|
style = buttonStyle
|
|
val d = new JFXDialog()
|
|
d.setContent(new HBox {
|
|
children = Seq(new Label("hmm"))
|
|
padding = Insets(20)
|
|
})
|
|
d.styleClass ++= Seq("text-white")
|
|
onAction = () => d.show(root)
|
|
}
|
|
)
|
|
}
|
|
}
|
|
})
|
|
)
|
|
} yield mainSceneNode
|
|
}
|
|
|
|
class TestModel(_name: String, _age: Int) {
|
|
val name = StringProperty(_name).readOnly
|
|
val age = ObjectProperty(_age).readOnly
|
|
}
|
|
|
|
object Test {
|
|
val items = ObservableBuffer(
|
|
new TestModel("hmm", 1),
|
|
new TestModel("hmm2", 2)
|
|
)
|
|
|
|
val ttv = new TableView[TestModel](items) {
|
|
columns ++= Seq(
|
|
new TableColumn[TestModel, String] {
|
|
text = "Name"
|
|
cellValueFactory = { _.value.name }
|
|
},
|
|
new TableColumn[TestModel, Int] {
|
|
text = "Age"
|
|
cellValueFactory = { _.value.age }
|
|
}
|
|
)
|
|
}
|
|
}
|