Skip to content

Commit 3ad3654

Browse files
committed
Gradle Runner visual styling
1 parent bc063e8 commit 3ad3654

5 files changed

Lines changed: 135 additions & 58 deletions

File tree

.idea/jarRepositories.xml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ compose.desktop {
7272
entitlementsFile.set(file("macos/entitlements.plist"))
7373
runtimeEntitlementsFile.set(file("macos/entitlements.plist"))
7474
appStore = true
75+
jvmArgs("-Dsun.java2d.metal=true")
7576
}
7677
windows{
7778
iconFile = rootProject.file("build/windows/processing.ico")

app/src/processing/app/gradle/GradleService.kt

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import javax.swing.SwingUtilities
1717
import javax.swing.event.DocumentEvent
1818
import javax.swing.event.DocumentListener
1919

20-
20+
// TODO: Embed the core, gradle plugin, and preprocessor in a custom .m2 repository
21+
// Right now the gradle service only works if you publish those to the local maven repository
2122
class GradleService(val editor: Editor) {
2223
val availableTasks = mutableStateListOf<String>()
2324
val finishedTasks = mutableStateListOf<String>()
@@ -54,20 +55,20 @@ class GradleService(val editor: Editor) {
5455

5556
run?.cancel()
5657
run = CoroutineScope(Dispatchers.IO).launch {
58+
running.value = true
5759
preparation?.join()
5860
cancel.cancel()
5961
cancel = GradleConnector.newCancellationTokenSource()
60-
connection.newSketchBuild()
61-
.forTasks("run")
62-
.withCancellationToken(cancel.token())
63-
.run()
64-
}
65-
66-
CoroutineScope(Dispatchers.IO).launch {
67-
running.value = true
68-
run?.join()
69-
running.value = false
62+
try {
63+
connection.newSketchBuild()
64+
.forTasks("run")
65+
.withCancellationToken(cancel.token())
66+
.run()
67+
}catch (e: Exception){
68+
Messages.log(e.toString())
69+
}
7070
}
71+
run?.invokeOnCompletion { running.value = run?.isActive ?: false }
7172
}
7273

7374
fun stop(){
@@ -83,6 +84,8 @@ class GradleService(val editor: Editor) {
8384

8485
// TODO: recreate connection if sketch folder changes
8586

87+
// TODO: Run the sketch with the latest changes
88+
8689
SwingUtilities.invokeLater {
8790
editor.sketch.code.forEach {
8891
it.document.addDocumentListener(object : DocumentListener {
@@ -109,10 +112,13 @@ class GradleService(val editor: Editor) {
109112

110113
fun ProjectConnection.newSketchBuild(): BuildLauncher{
111114
finishedTasks.clear()
115+
// TODO: Research if we can generate these programmatically
116+
// Ideally they would not be placed into the sketch folder
112117

113118
val buildGradle = folder.resolve("build.gradle.kts")
114119
if(!buildGradle.exists()){
115120
Messages.log("build.gradle.kts not found in ${folder}, creating one")
121+
// TODO: Allow for other plugins to be registered
116122
val content = """
117123
plugins{
118124
id("processing.java.gradle") version "${Base.getVersionName()}"
Lines changed: 108 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
package processing.app.gradle.ui
22

3+
import androidx.compose.animation.AnimatedVisibility
4+
import androidx.compose.animation.core.LinearEasing
5+
import androidx.compose.animation.core.tween
6+
import androidx.compose.animation.fadeIn
7+
import androidx.compose.animation.fadeOut
38
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.combinedClickable
59
import androidx.compose.foundation.layout.*
610
import androidx.compose.foundation.shape.CircleShape
711
import androidx.compose.material.*
812
import androidx.compose.material.icons.Icons
9-
import androidx.compose.material.icons.filled.Close
1013
import androidx.compose.material.icons.filled.PlayArrow
11-
import androidx.compose.runtime.Composable
14+
import androidx.compose.runtime.*
1215
import androidx.compose.ui.ExperimentalComposeUiApi
1316
import androidx.compose.ui.Modifier
1417
import androidx.compose.ui.awt.ComposePanel
1518
import androidx.compose.ui.awt.SwingPanel
1619
import androidx.compose.ui.draw.clip
1720
import androidx.compose.ui.graphics.Brush
1821
import androidx.compose.ui.graphics.Color
19-
import androidx.compose.ui.graphics.colorspace.ColorSpace
20-
import androidx.compose.ui.graphics.colorspace.ColorSpaces
2122
import androidx.compose.ui.input.pointer.PointerEventType
2223
import androidx.compose.ui.input.pointer.onPointerEvent
2324
import androidx.compose.ui.unit.dp
2425
import processing.app.ui.Editor
2526
import processing.app.ui.EditorToolbar
2627
import processing.app.ui.Theme
28+
import processing.app.ui.theme.toColorInt
2729
import javax.swing.JComponent
2830

2931
class Toolbar(val editor: Editor) {
3032
companion object{
3133
@JvmStatic
3234
fun legacyWrapped(editor: Editor, toolbar: EditorToolbar): JComponent {
35+
// TODO: Somehow override the menubar items as well
36+
3337
val bar = Toolbar(editor)
3438
val panel = ComposePanel().apply {
3539
setContent {
@@ -52,13 +56,13 @@ class Toolbar(val editor: Editor) {
5256
@OptIn(ExperimentalComposeUiApi::class)
5357
@Composable
5458
fun display(){
55-
56-
val startColor = Theme.getColor("toolbar.gradient.top")
57-
val endColor = Theme.getColor("toolbar.gradient.bottom")
59+
val startColor = Theme.get("toolbar.gradient.top").toColorInt()
60+
val endColor = Theme.get("toolbar.gradient.bottom").toColorInt()
5861
val colorStops = arrayOf(
59-
0.0f to startColor.toComposeColor(),
60-
1f to endColor.toComposeColor()
62+
0.0f to Color(startColor),
63+
1f to Color(endColor)
6164
)
65+
6266
Row(
6367
modifier = Modifier.background(Brush.verticalGradient(colorStops = colorStops))
6468
.fillMaxWidth()
@@ -70,59 +74,117 @@ class Toolbar(val editor: Editor) {
7074
val available = editor.service.availableTasks
7175
val finished = editor.service.finishedTasks
7276
val isRunning = editor.service.running.value
73-
Surface(
77+
ActionButton(
7478
modifier = Modifier
7579
.onPointerEvent(PointerEventType.Press){
7680
editor.service.run()
7781
}
78-
.height(34.dp)
79-
.clip(CircleShape)
80-
.aspectRatio(1f)
81-
.background(Color.White)
82-
83-
){
84-
if(isRunning) {
82+
.padding(1.dp)
83+
) {
84+
val color = LocalContentColor.current
85+
Fading(visible = isRunning) {
8586
CircularProgressIndicator(
86-
progress = finished.count().toFloat() / available.count() ,
87-
color = startColor.toComposeColor()
87+
progress = finished.count().toFloat() / (available.count() - 1),
88+
color = color
89+
)
90+
}
91+
Box(modifier = Modifier.padding(4.dp)) {
92+
Icon(
93+
imageVector = Icons.Filled.PlayArrow,
94+
contentDescription = "Play",
95+
tint = color
8896
)
8997
}
90-
Icon(
91-
imageVector = Icons.Filled.PlayArrow,
92-
contentDescription = "Play",
93-
tint = Color.Black,
94-
modifier = Modifier
95-
.size(2.dp)
96-
)
9798
}
98-
if(isRunning){
99-
Surface(
99+
Fading(visible = isRunning) {
100+
ActionButton(
100101
modifier = Modifier
101102
.onPointerEvent(PointerEventType.Press){
102103
editor.service.stop()
103104
}
104-
.height(34.dp)
105-
.clip(CircleShape)
106-
.aspectRatio(1f)
107-
.background(Color.White)
108-
) {
109-
Icon(
110-
imageVector = Icons.Filled.Close,
111-
contentDescription = "Stop",
112-
tint = Color.Black,
113-
modifier = Modifier.size(12.dp)
105+
){
106+
val color = LocalContentColor.current
107+
Box(
108+
modifier = Modifier
109+
.padding(12.dp)
110+
.size(12.dp)
111+
.background(color)
114112
)
115113
}
116114
}
117115
}
118116
}
119117
}
120118

121-
fun java.awt.Color.toComposeColor(): Color {
122-
return Color(
123-
red = this.red / 255f,
124-
green = this.green / 255f,
125-
blue = this.blue / 255f,
126-
alpha = this.alpha / 255f
127-
)
119+
@OptIn(ExperimentalComposeUiApi::class)
120+
@Composable
121+
fun ActionButton(modifier: Modifier = Modifier, content: @Composable () -> Unit){
122+
val baseColor = Theme.get("toolbar.button.enabled.field")
123+
val baseTextColor = Theme.get("toolbar.button.enabled.glyph")
124+
125+
var hover by remember{ mutableStateOf(false) }
126+
val hoverColor = Theme.get("toolbar.button.rollover.field")
127+
val hoverTextColor = Theme.get("toolbar.button.rollover.glyph")
128+
129+
var pressed by remember{ mutableStateOf(false) }
130+
val pressedColor = Theme.get("toolbar.button.pressed.field")
131+
val pressedTextColor = Theme.get("toolbar.button.pressed.glyph")
132+
133+
val color = when {
134+
pressed -> pressedColor
135+
hover -> hoverColor
136+
else -> baseColor
137+
}.toColorInt()
138+
139+
val textColor = when{
140+
pressed -> pressedTextColor
141+
hover -> hoverTextColor
142+
else -> baseTextColor
143+
}
144+
145+
Box(
146+
modifier = Modifier
147+
.onPointerEvent(PointerEventType.Enter) {
148+
hover = true
149+
}
150+
.onPointerEvent(PointerEventType.Exit) {
151+
hover = false
152+
}
153+
.onPointerEvent(PointerEventType.Press) {
154+
pressed = true
155+
}
156+
.onPointerEvent(PointerEventType.Release) {
157+
pressed = false
158+
}
159+
.height(34.dp)
160+
.clip(CircleShape)
161+
.aspectRatio(1f)
162+
.background(color = Color(color))
163+
.then(modifier)
164+
) {
165+
CompositionLocalProvider(LocalContentColor provides Color(textColor.toColorInt())) {
166+
content()
167+
}
168+
}
169+
}
170+
171+
@Composable
172+
fun Fading(visible: Boolean, content: @Composable () -> Unit) {
173+
AnimatedVisibility(
174+
visible = visible,
175+
enter = fadeIn(
176+
animationSpec = tween(
177+
durationMillis = 250,
178+
easing = LinearEasing
179+
)
180+
),
181+
exit = fadeOut(
182+
animationSpec = tween(
183+
durationMillis = 250,
184+
easing = LinearEasing
185+
)
186+
)
187+
) {
188+
content()
189+
}
128190
}

app/src/processing/app/ui/theme/Theme.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import androidx.compose.ui.graphics.Color
1010
import processing.app.LocalPreferences
1111
import processing.app.PreferencesProvider
1212
import java.io.InputStream
13-
import java.util.Properties
13+
import java.util.*
1414

1515

1616
class Theme(themeFile: String? = "") : Properties() {
@@ -71,5 +71,8 @@ fun String.toColorInt(): Int {
7171
}
7272
return color.toInt()
7373
}
74+
if (this.startsWith("0x")) {
75+
return this.substring(2).toInt(16)
76+
}
7477
throw IllegalArgumentException("Unknown color")
7578
}

0 commit comments

Comments
 (0)