blob: 8db651f65488dde8881e725597248bc6e006bdbb [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
2 * Copyright 2016-2017 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Roman Elizarovfbb36d32017-01-23 16:03:54 +030017package examples
18
Roman Elizarov3754f952017-01-18 20:47:54 +030019import javafx.application.Application
20import javafx.scene.Node
21import javafx.scene.Scene
22import javafx.scene.control.Button
23import javafx.scene.layout.FlowPane
24import javafx.scene.layout.Pane
25import javafx.scene.paint.Color
26import javafx.scene.shape.Circle
27import javafx.scene.shape.Rectangle
28import javafx.stage.Stage
Roman Elizarovfbb36d32017-01-23 16:03:54 +030029import kotlinx.coroutines.experimental.CoroutineScope
Roman Elizarov3754f952017-01-18 20:47:54 +030030import kotlinx.coroutines.experimental.Job
31import kotlinx.coroutines.experimental.delay
32import kotlinx.coroutines.experimental.javafx.JavaFx
33import kotlinx.coroutines.experimental.launch
Roman Elizarov49ebab92017-01-24 12:20:06 +030034import java.text.SimpleDateFormat
Roman Elizarov3754f952017-01-18 20:47:54 +030035import java.util.*
36
37fun main(args: Array<String>) {
38 Application.launch(FxTestApp::class.java, *args)
39}
40
Roman Elizarovb5331122017-02-08 16:33:07 +030041fun log(msg: String) = println("${SimpleDateFormat("yyyyMMdd-HHmmss.sss").format(Date())} [${Thread.currentThread().name}] $msg")
Roman Elizarov3754f952017-01-18 20:47:54 +030042
43class FxTestApp : Application() {
44 val buttons = FlowPane().apply {
45 children += Button("Rect").apply {
46 setOnAction { doRect() }
47 }
48 children += Button("Circle").apply {
49 setOnAction { doCircle() }
50 }
51 children += Button("Clear").apply {
52 setOnAction { doClear() }
53 }
54 }
55
56 val root = Pane().apply {
57 children += buttons
58 }
59
60 val scene = Scene(root, 600.0, 400.0)
61
Roman Elizarov23f864e2017-03-03 19:57:47 +030062 override fun start(stage: Stage) {
63 stage.title = "Hello world!"
64 stage.scene = scene
65 stage.show()
Roman Elizarov3754f952017-01-18 20:47:54 +030066 }
67
68 val random = Random()
69 val animations = arrayListOf<Job>()
70 var animationIndex = 0
71
Roman Elizarovfbb36d32017-01-23 16:03:54 +030072 private fun animation(node: Node, block: suspend CoroutineScope.() -> Unit) {
Roman Elizarov3754f952017-01-18 20:47:54 +030073 root.children += node
Roman Elizarov32d95322017-02-09 15:57:31 +030074 val job = launch(JavaFx, block = block)
Roman Elizarov3754f952017-01-18 20:47:54 +030075 animations += job
Roman Elizarove7803472017-02-16 09:52:31 +030076 job.invokeOnCompletion { root.children -= node }
Roman Elizarov3754f952017-01-18 20:47:54 +030077 }
78
79 fun doRect() {
80 val node = Rectangle(20.0, 20.0).apply {
81 fill = Color.RED
82 }
83 val index = ++animationIndex
84 val speed = 5.0
85 animation(node) {
86 log("Started new 'rect' coroutine #$index")
87 var vx = speed
88 var vy = speed
89 var counter = 0
90 while (true) {
91 JavaFx.awaitPulse()
92 node.x += vx
93 node.y += vy
94 val xRange = 0.0 .. scene.width - node.width
95 val yRange = 0.0 .. scene.height - node.height
96 if (node.x !in xRange ) {
97 node.x = node.x.coerceIn(xRange)
98 vx = -vx
99 }
100 if (node.y !in yRange) {
101 node.y = node.y.coerceIn(yRange)
102 vy = -vy
103 }
104 if (counter++ > 100) {
105 counter = 0
106 delay(1000) // pause a bit
107 log("Delayed #$index for a while, resume and turn")
108 val t = vx
109 vx = vy
110 vy = -t
111 }
112 }
113 }
114 }
115
116 fun doCircle() {
117 val node = Circle(20.0).apply {
118 fill = Color.BLUE
119 }
120 val index = ++animationIndex
121 val acceleration = 0.1
122 val maxSpeed = 5.0
123 animation(node) {
124 log("Started new 'circle' coroutine #$index")
125 var sx = random.nextDouble() * maxSpeed
126 var sy = random.nextDouble() * maxSpeed
127 while (true) {
128 JavaFx.awaitPulse()
129 val dx = root.width / 2 - node.translateX
130 val dy = root.height / 2 - node.translateY
131 val dn = Math.sqrt(dx * dx + dy * dy)
132 sx += dx / dn * acceleration
133 sy += dy / dn * acceleration
134 val sn = Math.sqrt(sx * sx + sy * sy)
135 val trim = sn.coerceAtMost(maxSpeed)
136 sx = sx / sn * trim
137 sy = sy / sn * trim
138 node.translateX += sx
139 node.translateY += sy
140 }
141 }
142 }
143
144 fun doClear() {
145 animations.forEach { it.cancel() }
146 }
147}