diff --git a/platform/jewel/.github/workflows/build.yml b/platform/jewel/.github/workflows/build.yml
index 1700658a8275..dc763b0f1002 100644
--- a/platform/jewel/.github/workflows/build.yml
+++ b/platform/jewel/.github/workflows/build.yml
@@ -39,13 +39,15 @@ jobs:
run: chmod +x gradlew
- name: Run :check task
- run: ./gradlew check
+ run: ./gradlew check --continue
- name: Merge SARIF reports
# Necessary because upload-sarif only takes up to 15 SARIF files and we have more
run: ./gradlew :mergeSarifReports
+ if: ${{ always() }}
- uses: github/codeql-action/upload-sarif@v2
+ if: ${{ always() }}
with:
sarif_file: ${{ github.workspace }}/build/reports/static-analysis.sarif
checkout_path: ${{ github.workspace }}
diff --git a/platform/jewel/.idea/codeStyles/Project.xml b/platform/jewel/.idea/codeStyles/Project.xml
index e5663699aa58..5383e2d02f00 100644
--- a/platform/jewel/.idea/codeStyles/Project.xml
+++ b/platform/jewel/.idea/codeStyles/Project.xml
@@ -19,6 +19,9 @@
+
+
+
diff --git a/platform/jewel/.idea/inspectionProfiles/Lint_only.xml b/platform/jewel/.idea/inspectionProfiles/Lint_only.xml
new file mode 100644
index 000000000000..ebf8bbd10973
--- /dev/null
+++ b/platform/jewel/.idea/inspectionProfiles/Lint_only.xml
@@ -0,0 +1,1085 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/platform/jewel/.idea/inspectionProfiles/Project_Default.xml b/platform/jewel/.idea/inspectionProfiles/Project_Default.xml
index 71e3f1aedaf0..073a9ce90d31 100644
--- a/platform/jewel/.idea/inspectionProfiles/Project_Default.xml
+++ b/platform/jewel/.idea/inspectionProfiles/Project_Default.xml
@@ -1,315 +1,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
\ No newline at end of file
diff --git a/platform/jewel/.idea/runConfigurations/IDE_sample.xml b/platform/jewel/.idea/runConfigurations/IDE_sample.xml
index 3ba7c5d9c4f1..c62c0a8086fb 100644
--- a/platform/jewel/.idea/runConfigurations/IDE_sample.xml
+++ b/platform/jewel/.idea/runConfigurations/IDE_sample.xml
@@ -1,5 +1,6 @@
+
@@ -18,6 +19,7 @@
true
true
false
+ false
\ No newline at end of file
diff --git a/platform/jewel/README.md b/platform/jewel/README.md
index ea085605ecb7..eb5cb71b9925 100644
--- a/platform/jewel/README.md
+++ b/platform/jewel/README.md
@@ -1,14 +1,18 @@
[](https://github.com/JetBrains#jetbrains-on-github) [](https://github.com/JetBrains/jewel/actions/workflows/build.yml)
+
# Jewel: a Compose for Desktop theme
-Jewel aims at recreating the _Darcula_ and _New UI_ Swing Look and Feels used on the IntelliJ Platform into Compose for Desktop.
+Jewel aims at recreating the _Darcula_ and _New UI_ Swing Look and Feels used on the IntelliJ Platform into Compose for
+Desktop.
> **Warning**
->This project is in very early development and is probably not ready to be used in production projects. You _can_, but there
->are no published snapshots, and you should expect APIs to break fairly often, things to move around, and all that jazz.
->Use at your risk!
+> This project is in very early development and is probably not ready to be used in production projects. You _can_, but
+> there
+> are no published snapshots, and you should expect APIs to break fairly often, things to move around, and all that
+> jazz.
+> Use at your risk!
## Project structure
@@ -19,7 +23,8 @@ The project is split in modules:
3. `themes` are the two themes implemented by Jewel:
1. `darcula` is the old school Intellij LaF, called Darcula, which has two implementations:
1. `darcula-standalone` is the base theme and can be used in any Compose for Desktop project
- 2. `darcula-ide` is a version of the theme that can be used in an IDEA plugin, and integrates with the IDE's Swing LaF and themes via a
+ 2. `darcula-ide` is a version of the theme that can be used in an IDEA plugin, and integrates with the IDE's
+ Swing LaF and themes via a
bridge (more
on that later)
2. `new-ui` implements the new IntelliJ LaF, known as "new UI". This also has the same two implementations
@@ -31,29 +36,45 @@ The project is split in modules:
To run the stand-alone sample app, you can run the `:samples:standalone:run` Gradle task.
-To run the IntelliJ IDEA plugin sample, you can run the `:samples:ide-plugin:runIde` Gradle task. This will download and run a copy of IJ Community
-with the plugin installed; you can check the additional panels in the IDE once it starts up (at the bottom, by default, in old UI; in the overflow
+To run the IntelliJ IDEA plugin sample, you can run the `:samples:ide-plugin:runIde` Gradle task. This will download and
+run a copy of IJ Community
+with the plugin installed; you can check the additional panels in the IDE once it starts up (at the bottom, by default,
+in old UI; in the overflow
in the new UI).
If you're using IntelliJ IDEA, you can use the "Stand-alone sample" and "IDE sample" run configurations.
### The Swing Bridge
-In the `*-ide` modules, there is a crucial element for proper integration with the IDE: a bridge between the Swing theme and LaF, and the Compose
+In the `*-ide` modules, there is a crucial element for proper integration with the IDE: a bridge between the Swing theme
+and LaF, and the Compose
world.
-This bridge ensures that we pick up the colours, typography, metrics, and images as defined in the current IntelliJ theme, and apply them to the
+This bridge ensures that we pick up the colours, typography, metrics, and images as defined in the current IntelliJ
+theme, and apply them to the
Compose theme as well.
-The work of building this bridge is fairly complex as there isn't a good mapping between the IDE LaF properties, the Darcula design specs, and the
+The work of building this bridge is fairly complex as there isn't a good mapping between the IDE LaF properties, the
+Darcula design specs, and the
Compose implementations. Sometimes, you will need to get a bit creative.
-When adding a new composable to the IJ theme, you need to make sure you also update the bridge to properly support it at runtime. You can refer to the
-[Darcula design specs](https://jetbrains.design/intellij) and corresponding [Figma specs](https://jetbrains.design/intellij/resources/UI_kit/), but
-the ultimate goal is consistency with the Swing implementation, so the ground truth of what you see in the IDE is the reference for any implementation
+When adding a new composable to the IJ theme, you need to make sure you also update the bridge to properly support it at
+runtime. You can refer to the
+[Darcula design specs](https://jetbrains.design/intellij) and
+corresponding [Figma specs](https://jetbrains.design/intellij/resources/UI_kit/), but
+the ultimate goal is consistency with the Swing implementation, so the ground truth of what you see in the IDE is the
+reference for any implementation
and trumps the specs.
To find the required values in the IDE, we recommend enabling
the [IDE internal mode](https://plugins.jetbrains.com/docs/intellij/enabling-internal.html)
and using the [UI Inspector](https://plugins.jetbrains.com/docs/intellij/internal-ui-inspector.html) and
-[LaF Defaults](https://plugins.jetbrains.com/docs/intellij/internal-ui-laf-defaults.html) tools to figure out the names of the parameters to use in
+[LaF Defaults](https://plugins.jetbrains.com/docs/intellij/internal-ui-laf-defaults.html) tools to figure out the names
+of the parameters to use in
the bridge.
+
+To see debug logs in the IDE, add these to __Help | Diagnostic Tools | Debug Log Settings__:
+
+```
+#org.jetbrains.jewel.demo
+#org.jetbrains.jewel
+```
diff --git a/platform/jewel/build.gradle.kts b/platform/jewel/build.gradle.kts
index 2fb3b8e46fdd..ee13bb71d6a8 100644
--- a/platform/jewel/build.gradle.kts
+++ b/platform/jewel/build.gradle.kts
@@ -10,7 +10,6 @@ val sarif: Configuration by configurations.creating {
}
dependencies {
- sarif(projects.foundation)
sarif(projects.core)
sarif(projects.composeUtils)
sarif(projects.samples.standalone)
diff --git a/platform/jewel/buildSrc/src/main/kotlin/jewel.gradle.kts b/platform/jewel/buildSrc/src/main/kotlin/jewel.gradle.kts
index 96192850ba8b..2bdb5ddb9156 100644
--- a/platform/jewel/buildSrc/src/main/kotlin/jewel.gradle.kts
+++ b/platform/jewel/buildSrc/src/main/kotlin/jewel.gradle.kts
@@ -35,6 +35,7 @@ kotlin {
optIn("kotlin.experimental.ExperimentalTypeInference")
optIn("androidx.compose.ui.ExperimentalComposeUiApi")
optIn("androidx.compose.foundation.ExperimentalFoundationApi")
+ optIn("org.jetbrains.jewel.ExperimentalJewelApi")
}
}
}
diff --git a/platform/jewel/buildSrc/src/main/kotlin/org/jetbrains/jewel/buildlogic/theme/IntelliJThemeGeneratorPlugin.kt b/platform/jewel/buildSrc/src/main/kotlin/org/jetbrains/jewel/buildlogic/theme/IntelliJThemeGeneratorPlugin.kt
index 5b51e8cb3ed5..c6f025d856c3 100644
--- a/platform/jewel/buildSrc/src/main/kotlin/org/jetbrains/jewel/buildlogic/theme/IntelliJThemeGeneratorPlugin.kt
+++ b/platform/jewel/buildSrc/src/main/kotlin/org/jetbrains/jewel/buildlogic/theme/IntelliJThemeGeneratorPlugin.kt
@@ -2,7 +2,6 @@ package org.jetbrains.jewel.buildlogic.theme
import com.squareup.kotlinpoet.ClassName
import io.gitlab.arturbosch.detekt.Detekt
-import java.net.URL
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
@@ -23,7 +22,8 @@ import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.withType
import org.gradle.util.internal.GUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.jetbrains.kotlin.gradle.tasks.BaseKotlinCompile
+import java.net.URL
abstract class IntelliJThemeGeneratorPlugin : Plugin {
@@ -42,7 +42,7 @@ abstract class IntelliJThemeGeneratorPlugin : Plugin {
ideaVersion.set(this@all.ideaVersion)
themeFile.set(this@all.themeFile)
}
- tasks.withType {
+ tasks.withType {
dependsOn(task)
}
tasks.withType {
diff --git a/platform/jewel/compose-utils/build.gradle.kts b/platform/jewel/compose-utils/build.gradle.kts
index 802760bc16b7..eabbd39c0160 100644
--- a/platform/jewel/compose-utils/build.gradle.kts
+++ b/platform/jewel/compose-utils/build.gradle.kts
@@ -7,6 +7,5 @@ dependencies {
api(compose.desktop.currentOs) {
exclude(group = "org.jetbrains.compose.material")
}
- implementation(libs.jna)
implementation(libs.kotlinx.serialization.json)
}
diff --git a/platform/jewel/core/build.gradle.kts b/platform/jewel/core/build.gradle.kts
index 585ece4a27ee..ba1a41021360 100644
--- a/platform/jewel/core/build.gradle.kts
+++ b/platform/jewel/core/build.gradle.kts
@@ -6,6 +6,5 @@ plugins {
dependencies {
api(projects.composeUtils)
- api(projects.foundation)
api(compose.desktop.common)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Button.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Button.kt
index 55d5cccdd1fe..b36897e9b282 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Button.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Button.kt
@@ -29,11 +29,9 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.TextStyle
import org.jetbrains.jewel.CommonStateBitMask.Active
import org.jetbrains.jewel.CommonStateBitMask.Enabled
-import org.jetbrains.jewel.CommonStateBitMask.Error
import org.jetbrains.jewel.CommonStateBitMask.Focused
import org.jetbrains.jewel.CommonStateBitMask.Hovered
import org.jetbrains.jewel.CommonStateBitMask.Pressed
-import org.jetbrains.jewel.CommonStateBitMask.Warning
import org.jetbrains.jewel.foundation.Stroke
import org.jetbrains.jewel.foundation.border
import org.jetbrains.jewel.styling.ButtonStyle
@@ -55,7 +53,7 @@ fun DefaultButton(
interactionSource = interactionSource,
style = style,
content = content,
- textStyle = textStyle
+ textStyle = textStyle,
)
}
@@ -76,7 +74,7 @@ fun OutlinedButton(
interactionSource = interactionSource,
style = style,
content = content,
- textStyle = textStyle
+ textStyle = textStyle,
)
}
@@ -117,23 +115,27 @@ private fun ButtonImpl(
val shape = RoundedCornerShape(style.metrics.cornerSize)
val colors = style.colors
val borderColor by colors.borderFor(buttonState)
+ println("state: $buttonState ($enabled) -> $borderColor")
Box(
- modifier.clickable(
- onClick = onClick,
- enabled = enabled,
- role = Role.Button,
- interactionSource = interactionSource,
- indication = null
- ).background(colors.backgroundFor(buttonState).value, shape)
+ modifier = modifier
+ .clickable(
+ onClick = onClick,
+ enabled = enabled,
+ role = Role.Button,
+ interactionSource = interactionSource,
+ indication = null,
+ )
+ .background(colors.backgroundFor(buttonState).value, shape)
.border(Stroke.Alignment.Center, style.metrics.borderWidth, borderColor, shape)
.focusOutline(buttonState, shape),
- propagateMinConstraints = true
+ propagateMinConstraints = true,
) {
val contentColor by colors.contentFor(buttonState)
+
CompositionLocalProvider(
LocalContentColor provides contentColor.takeOrElse { textStyle.color },
- LocalTextStyle provides textStyle.copy(color = contentColor.takeOrElse { textStyle.color })
+ LocalTextStyle provides textStyle.copy(color = contentColor.takeOrElse { textStyle.color }),
) {
Row(
Modifier
@@ -141,7 +143,7 @@ private fun ButtonImpl(
.padding(style.metrics.padding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
- content = content
+ content = content,
)
}
}
@@ -182,7 +184,7 @@ value class ButtonState(val state: ULong) : FocusableComponentState {
focused = focused,
pressed = pressed,
hovered = hovered,
- active = active
+ active = active,
)
override fun toString() =
@@ -194,19 +196,15 @@ value class ButtonState(val state: ULong) : FocusableComponentState {
fun of(
enabled: Boolean = true,
focused: Boolean = false,
- error: Boolean = false,
pressed: Boolean = false,
hovered: Boolean = false,
- warning: Boolean = false,
active: Boolean = true,
) = ButtonState(
state = (if (enabled) Enabled else 0UL) or
(if (focused) Focused else 0UL) or
(if (hovered) Hovered else 0UL) or
(if (pressed) Pressed else 0UL) or
- (if (warning) Warning else 0UL) or
- (if (error) Error else 0UL) or
- (if (active) Active else 0UL)
+ (if (active) Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Checkbox.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Checkbox.kt
index c0a285259ef4..23f6693331f4 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Checkbox.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Checkbox.kt
@@ -71,7 +71,7 @@ fun Checkbox(
icons = icons,
textStyle = textStyle,
resourceLoader = resourceLoader,
- content = null
+ content = null,
)
}
@@ -101,7 +101,7 @@ fun TriStateCheckbox(
icons = icons,
textStyle = textStyle,
resourceLoader = resourceLoader,
- content = null
+ content = null,
)
}
@@ -131,7 +131,7 @@ fun TriStateCheckboxRow(
metrics = metrics,
icons = icons,
resourceLoader = resourceLoader,
- textStyle = textStyle
+ textStyle = textStyle,
) {
Text(text)
}
@@ -165,7 +165,7 @@ fun CheckboxRow(
metrics = metrics,
icons = icons,
resourceLoader = resourceLoader,
- textStyle = textStyle
+ textStyle = textStyle,
) {
Text(text)
}
@@ -200,7 +200,7 @@ fun CheckboxRow(
icons = icons,
resourceLoader = resourceLoader,
textStyle = textStyle,
- content = content
+ content = content,
)
}
@@ -231,7 +231,7 @@ fun TriStateCheckboxRow(
icons = icons,
resourceLoader = resourceLoader,
textStyle = textStyle,
- content = content
+ content = content,
)
}
@@ -280,16 +280,16 @@ private fun CheckboxImpl(
enabled = enabled,
role = Role.Checkbox,
interactionSource = interactionSource,
- indication = null
+ indication = null,
)
val checkBoxImageModifier = Modifier.size(metrics.checkboxSize)
.outline(
state = checkboxState,
outline = outline,
- alignment = Stroke.Alignment.Center,
outlineShape = RoundedCornerShape(metrics.checkboxCornerSize),
- outlineWidth = metrics.outlineWidth
+ alignment = Stroke.Alignment.Center,
+ outlineWidth = metrics.outlineWidth,
)
val checkboxPainter by icons.checkbox.getPainter(checkboxState, resourceLoader)
@@ -300,14 +300,14 @@ private fun CheckboxImpl(
Row(
wrapperModifier,
horizontalArrangement = Arrangement.spacedBy(metrics.iconContentGap),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
CheckBoxImage(Modifier, checkboxPainter, checkBoxImageModifier)
val contentColor by colors.contentFor(checkboxState)
CompositionLocalProvider(
LocalTextStyle provides textStyle.copy(color = contentColor.takeOrElse { textStyle.color }),
- LocalContentColor provides contentColor.takeOrElse { textStyle.color }
+ LocalContentColor provides contentColor.takeOrElse { textStyle.color },
) {
content()
}
@@ -367,7 +367,7 @@ value class CheckboxState(private val state: ULong) : ToggleableComponentState {
focused = focused,
pressed = pressed,
hovered = hovered,
- active = active
+ active = active,
)
override fun toString() =
@@ -390,7 +390,7 @@ value class CheckboxState(private val state: ULong) : ToggleableComponentState {
(if (pressed) Pressed else 0UL) or
(if (toggleableState != ToggleableState.Off) Selected else 0UL) or
(if (toggleableState == ToggleableState.Indeterminate) Indeterminate else 0UL) or
- (if (active) Active else 0UL)
+ (if (active) Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Chip.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Chip.kt
index 6195925d671e..6ebc64ba45c5 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Chip.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Chip.kt
@@ -8,8 +8,9 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.selection.selectable
+import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@@ -26,11 +27,10 @@ import androidx.compose.ui.graphics.isUnspecified
import androidx.compose.ui.semantics.Role
import org.jetbrains.jewel.CommonStateBitMask.Active
import org.jetbrains.jewel.CommonStateBitMask.Enabled
-import org.jetbrains.jewel.CommonStateBitMask.Error
import org.jetbrains.jewel.CommonStateBitMask.Focused
import org.jetbrains.jewel.CommonStateBitMask.Hovered
import org.jetbrains.jewel.CommonStateBitMask.Pressed
-import org.jetbrains.jewel.CommonStateBitMask.Warning
+import org.jetbrains.jewel.CommonStateBitMask.Selected
import org.jetbrains.jewel.foundation.Stroke
import org.jetbrains.jewel.foundation.border
import org.jetbrains.jewel.styling.ChipStyle
@@ -40,15 +40,95 @@ fun Chip(
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
enabled: Boolean = true,
+ selected: Boolean = false,
style: ChipStyle = IntelliJTheme.chipStyle,
- onChipClick: () -> Unit = {},
+ onClick: () -> Unit = {},
+ content: @Composable () -> Unit,
+) {
+ ChipImpl(
+ interactionSource = interactionSource,
+ enabled = enabled,
+ selected = selected,
+ style = style,
+ modifier = modifier.clickable(
+ onClick = onClick,
+ enabled = enabled,
+ role = Role.Button,
+ interactionSource = interactionSource,
+ indication = null,
+ ),
+ content = content,
+ )
+}
+
+@Composable
+fun ToggleableChip(
+ checked: Boolean,
+ onClick: (Boolean) -> Unit,
+ modifier: Modifier = Modifier,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ enabled: Boolean = true,
+ style: ChipStyle = IntelliJTheme.chipStyle,
+ content: @Composable () -> Unit,
+) {
+ ChipImpl(
+ interactionSource = interactionSource,
+ enabled = enabled,
+ selected = checked,
+ style = style,
+ modifier = modifier.toggleable(
+ onValueChange = onClick,
+ enabled = enabled,
+ role = Role.Checkbox,
+ interactionSource = interactionSource,
+ indication = null,
+ value = checked,
+ ),
+ content = content,
+ )
+}
+
+@Composable
+fun RadioButtonChip(
+ selected: Boolean,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ enabled: Boolean = true,
+ style: ChipStyle = IntelliJTheme.chipStyle,
+ content: @Composable () -> Unit,
+) {
+ ChipImpl(
+ interactionSource,
+ enabled,
+ selected,
+ style,
+ modifier.selectable(
+ onClick = onClick,
+ enabled = enabled,
+ role = Role.RadioButton,
+ interactionSource = interactionSource,
+ indication = null,
+ selected = selected,
+ ),
+ content,
+ )
+}
+
+@Composable
+private fun ChipImpl(
+ interactionSource: MutableInteractionSource,
+ enabled: Boolean,
+ selected: Boolean,
+ style: ChipStyle,
+ modifier: Modifier,
content: @Composable () -> Unit,
) {
var chipState by remember(interactionSource) {
- mutableStateOf(ChipState.of(enabled = enabled))
+ mutableStateOf(ChipState.of(enabled = enabled, selected = selected))
}
- remember(enabled) {
- chipState = chipState.copy(enabled = enabled)
+ remember(enabled, selected) {
+ chipState = chipState.copy(enabled = enabled, selected = selected)
}
LaunchedEffect(interactionSource) {
@@ -70,20 +150,12 @@ fun Chip(
Row(
modifier = modifier
- .clickable(
- onClick = onChipClick,
- enabled = enabled,
- role = Role.Button,
- interactionSource = interactionSource,
- indication = null
- )
- .padding(style.metrics.padding)
- .defaultMinSize(style.metrics.minSize.width, style.metrics.minSize.height)
.background(colors.backgroundFor(chipState).value, shape)
.border(Stroke.Alignment.Center, style.metrics.borderWidth, borderColor, shape)
- .outline(chipState, shape),
+ .focusOutline(chipState, shape)
+ .padding(style.metrics.padding),
verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center
+ horizontalArrangement = Arrangement.Center,
) {
CompositionLocalProvider(
LocalContentColor provides (
@@ -92,7 +164,7 @@ fun Chip(
.value
.takeIf { !it.isUnspecified }
?: LocalContentColor.current
- )
+ ),
) {
content()
}
@@ -101,7 +173,7 @@ fun Chip(
@Immutable
@JvmInline
-value class ChipState(val state: ULong) : StateWithOutline {
+value class ChipState(val state: ULong) : FocusableComponentState, SelectableComponentState {
@Stable
override val isActive: Boolean
@@ -116,12 +188,8 @@ value class ChipState(val state: ULong) : StateWithOutline {
get() = state and Focused != 0UL
@Stable
- override val isError: Boolean
- get() = state and Error != 0UL
-
- @Stable
- override val isWarning: Boolean
- get() = state and Warning != 0UL
+ override val isSelected: Boolean
+ get() = state and Selected != 0UL
@Stable
override val isHovered: Boolean
@@ -134,23 +202,21 @@ value class ChipState(val state: ULong) : StateWithOutline {
fun copy(
enabled: Boolean = isEnabled,
focused: Boolean = isFocused,
- error: Boolean = isError,
+ selected: Boolean = isSelected,
pressed: Boolean = isPressed,
hovered: Boolean = isHovered,
- warning: Boolean = isWarning,
active: Boolean = isActive,
): ChipState = of(
enabled = enabled,
focused = focused,
- error = error,
pressed = pressed,
hovered = hovered,
- warning = warning,
- active = active
+ active = active,
+ selected = selected,
)
override fun toString() =
- "ChipState(isEnabled=$isEnabled, isFocused=$isFocused, isError=$isError, isWarning=$isWarning, " +
+ "ChipState(isEnabled=$isEnabled, isFocused=$isFocused, isSelected=$isSelected, " +
"isHovered=$isHovered, isPressed=$isPressed, isActive=$isActive)"
companion object {
@@ -158,19 +224,17 @@ value class ChipState(val state: ULong) : StateWithOutline {
fun of(
enabled: Boolean = true,
focused: Boolean = false,
- error: Boolean = false,
+ selected: Boolean = false,
pressed: Boolean = false,
hovered: Boolean = false,
- warning: Boolean = false,
active: Boolean = false,
) = ChipState(
state = (if (enabled) Enabled else 0UL) or
(if (focused) Focused else 0UL) or
- (if (error) Error else 0UL) or
+ (if (selected) Selected else 0UL) or
(if (hovered) Hovered else 0UL) or
(if (pressed) Pressed else 0UL) or
- (if (warning) Warning else 0UL) or
- (if (active) Active else 0UL)
+ (if (active) Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ContextMenu.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ContextMenu.kt
index f762f05537a3..63ef4c16d6cb 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ContextMenu.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ContextMenu.kt
@@ -15,7 +15,9 @@ import androidx.compose.ui.input.InputMode
import androidx.compose.ui.input.InputModeManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalInputModeManager
+import androidx.compose.ui.res.ResourceLoader
import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupProperties
import androidx.compose.ui.window.rememberCursorPositionProvider
import org.jetbrains.jewel.styling.MenuStyle
@@ -31,7 +33,8 @@ object IntelliJContextMenuRepresentation : ContextMenuRepresentation {
state.status = ContextMenuState.Status.Closed
true
},
- style = IntelliJTheme.menuStyle
+ style = IntelliJTheme.menuStyle,
+ resourceLoader = LocalResourceLoader.current,
) {
contextItems(items)
}
@@ -42,8 +45,9 @@ object IntelliJContextMenuRepresentation : ContextMenuRepresentation {
@Composable
internal fun ContextMenu(
onDismissRequest: (InputMode) -> Boolean,
- focusable: Boolean = true,
+ resourceLoader: ResourceLoader,
modifier: Modifier = Modifier,
+ focusable: Boolean = true,
style: MenuStyle = IntelliJTheme.menuStyle,
content: MenuScope.() -> Unit,
) {
@@ -51,31 +55,33 @@ internal fun ContextMenu(
var inputModeManager: InputModeManager? by mutableStateOf(null)
val menuManager = remember(onDismissRequest) {
MenuManager(
- onDismissRequest = onDismissRequest
+ onDismissRequest = onDismissRequest,
)
}
Popup(
- focusable = focusable,
+ popupPositionProvider = rememberCursorPositionProvider(style.metrics.offset),
onDismissRequest = {
onDismissRequest(InputMode.Touch)
},
- popupPositionProvider = rememberCursorPositionProvider(style.metrics.offset),
+ properties = PopupProperties(focusable = focusable),
+ onPreviewKeyEvent = { false },
onKeyEvent = {
val currentFocusManager = checkNotNull(focusManager) { "FocusManager must not be null" }
val currentInputModeManager = checkNotNull(inputModeManager) { "InputModeManager must not be null" }
handlePopupMenuOnKeyEvent(it, currentFocusManager, currentInputModeManager, menuManager)
- }
+ },
) {
focusManager = LocalFocusManager.current
inputModeManager = LocalInputModeManager.current
CompositionLocalProvider(
- LocalMenuManager provides menuManager
+ LocalMenuManager provides menuManager,
) {
MenuContent(
modifier = modifier,
- content = content
+ content = content,
+ resourceLoader = resourceLoader,
)
}
}
@@ -85,7 +91,7 @@ private fun MenuScope.contextItems(items: () -> List) {
items().forEach { item ->
when (item) {
is ContextMenuDivider -> {
- divider()
+ separator()
}
is ContextSubmenu -> {
@@ -99,7 +105,7 @@ private fun MenuScope.contextItems(items: () -> List) {
else -> {
selectableItem(
selected = false,
- onClick = item.onClick
+ onClick = item.onClick,
) {
Text(item.label)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/DisabledColorFilter.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/DisabledColorFilter.kt
new file mode 100644
index 000000000000..6259794d5eb4
--- /dev/null
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/DisabledColorFilter.kt
@@ -0,0 +1,29 @@
+package org.jetbrains.jewel
+
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.ColorMatrix
+
+// Implements javax.swing.GrayFilter's behaviour with percent = 50, brighter = true
+// to match the GrayFilter#createDisabledImage behavior, used by Swing.
+private val disabledColorMatrixGammaEncoded = ColorMatrix().apply {
+ val saturation = .5f
+
+ // We use NTSC luminance weights like Swing does as it's gamma-encoded RGB
+ val redFactor = .299f * saturation
+ val greenFactor = .587f * saturation
+ val blueFactor = .114f * saturation
+
+ // TODO we should also be scaling the brightness but it's not possible
+ // with a matrix transformation as far as I can tell
+ this[0, 0] = redFactor
+ this[0, 1] = greenFactor
+ this[0, 2] = blueFactor
+ this[1, 0] = redFactor
+ this[1, 1] = greenFactor
+ this[1, 2] = blueFactor
+ this[2, 0] = redFactor
+ this[2, 1] = greenFactor
+ this[2, 2] = blueFactor
+}
+
+fun ColorFilter.Companion.disabled(): ColorFilter = colorMatrix(disabledColorMatrixGammaEncoded)
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Divider.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Divider.kt
index f8bbd112164d..31c360dc84ff 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Divider.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Divider.kt
@@ -36,6 +36,6 @@ fun Divider(
modifier
.then(indentMod)
.then(orientationModifier)
- .background(color = color)
+ .background(color = color),
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Dropdown.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Dropdown.kt
index 3406b8175014..2b1ff6f70e55 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Dropdown.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Dropdown.kt
@@ -34,13 +34,12 @@ import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.res.ResourceLoader
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupProperties
import org.jetbrains.jewel.CommonStateBitMask.Active
import org.jetbrains.jewel.CommonStateBitMask.Enabled
-import org.jetbrains.jewel.CommonStateBitMask.Error
import org.jetbrains.jewel.CommonStateBitMask.Focused
import org.jetbrains.jewel.CommonStateBitMask.Hovered
import org.jetbrains.jewel.CommonStateBitMask.Pressed
-import org.jetbrains.jewel.CommonStateBitMask.Warning
import org.jetbrains.jewel.foundation.Stroke
import org.jetbrains.jewel.foundation.border
import org.jetbrains.jewel.styling.DropdownStyle
@@ -64,11 +63,11 @@ fun Dropdown(
var skipNextClick by remember { mutableStateOf(false) }
var dropdownState by remember(interactionSource) {
- mutableStateOf(DropdownState.of(enabled = enabled, outline = outline))
+ mutableStateOf(DropdownState.of(enabled = enabled))
}
- remember(enabled, outline) {
- dropdownState = dropdownState.copy(enabled = enabled, outline = Outline.Error)
+ remember(enabled) {
+ dropdownState = dropdownState.copy(enabled = enabled)
}
LaunchedEffect(interactionSource) {
@@ -91,6 +90,7 @@ fun Dropdown(
val metrics = style.metrics
val shape = RoundedCornerShape(style.metrics.cornerSize)
val minSize = metrics.minSize
+ val arrowMinSize = style.metrics.arrowMinSize
val borderColor by colors.borderFor(dropdownState)
Box(
@@ -105,33 +105,37 @@ fun Dropdown(
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
- indication = null
- ).background(colors.backgroundFor(dropdownState).value, shape)
+ indication = null,
+ )
+ .background(colors.backgroundFor(dropdownState).value, shape)
.border(Stroke.Alignment.Center, style.metrics.borderWidth, borderColor, shape)
- .defaultMinSize(minSize.width, minSize.height),
- contentAlignment = Alignment.CenterStart
+ .outline(dropdownState, outline, shape)
+ .defaultMinSize(minSize.width, minSize.height.coerceAtLeast(arrowMinSize.height)),
+ contentAlignment = Alignment.CenterStart,
) {
CompositionLocalProvider(
- LocalContentColor provides colors.contentFor(dropdownState).value
+ LocalContentColor provides colors.contentFor(dropdownState).value,
) {
Row(
- Modifier.padding(style.metrics.contentPadding).padding(end = minSize.height),
+ modifier = Modifier.padding(style.metrics.contentPadding)
+ .padding(end = minSize.height),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
content = {
content()
- }
+ },
)
Box(
- modifier = Modifier.size(minSize.height).align(Alignment.CenterEnd),
- contentAlignment = Alignment.Center
+ modifier = Modifier.size(arrowMinSize)
+ .align(Alignment.CenterEnd),
+ contentAlignment = Alignment.Center,
) {
val chevronIcon by style.icons.chevronDown.getPainter(dropdownState, resourceLoader)
Icon(
painter = chevronIcon,
contentDescription = null,
- tint = colors.iconTintFor(dropdownState).value
+ tint = colors.iconTintFor(dropdownState).value,
)
}
}
@@ -149,7 +153,8 @@ fun Dropdown(
modifier = menuModifier,
style = style.menuStyle,
horizontalAlignment = Alignment.Start,
- content = menuContent
+ content = menuContent,
+ resourceLoader = resourceLoader,
)
}
}
@@ -159,6 +164,7 @@ fun Dropdown(
internal fun DropdownMenu(
onDismissRequest: (InputMode) -> Boolean,
horizontalAlignment: Alignment.Horizontal,
+ resourceLoader: ResourceLoader,
modifier: Modifier = Modifier,
style: MenuStyle,
content: MenuScope.() -> Unit,
@@ -167,9 +173,9 @@ internal fun DropdownMenu(
val popupPositionProvider = AnchorVerticalMenuPositionProvider(
contentOffset = style.metrics.offset,
- contentMargin = style.metrics.margin,
+ contentMargin = style.metrics.menuMargin,
alignment = horizontalAlignment,
- density = density
+ density = density,
)
var focusManager: FocusManager? by mutableStateOf(null)
@@ -179,25 +185,27 @@ internal fun DropdownMenu(
}
Popup(
- onDismissRequest = { onDismissRequest(InputMode.Touch) },
popupPositionProvider = popupPositionProvider,
+ onDismissRequest = { onDismissRequest(InputMode.Touch) },
+ properties = PopupProperties(focusable = true),
+ onPreviewKeyEvent = { false },
onKeyEvent = {
val currentFocusManager = checkNotNull(focusManager) { "FocusManager must not be null" }
val currentInputModeManager = checkNotNull(inputModeManager) { "InputModeManager must not be null" }
handlePopupMenuOnKeyEvent(it, currentFocusManager, currentInputModeManager, menuManager)
},
- focusable = true
) {
focusManager = LocalFocusManager.current
inputModeManager = LocalInputModeManager.current
CompositionLocalProvider(
LocalMenuManager provides menuManager,
- LocalMenuStyle provides style
+ LocalMenuStyle provides style,
) {
MenuContent(
modifier = modifier,
- content = content
+ content = content,
+ resourceLoader = resourceLoader,
)
}
}
@@ -205,7 +213,7 @@ internal fun DropdownMenu(
@Immutable
@JvmInline
-value class DropdownState(val state: ULong) : StateWithOutline {
+value class DropdownState(val state: ULong) : FocusableComponentState {
@Stable
override val isActive: Boolean
@@ -219,14 +227,6 @@ value class DropdownState(val state: ULong) : StateWithOutline {
override val isFocused: Boolean
get() = state and Focused != 0UL
- @Stable
- override val isError: Boolean
- get() = state and Error != 0UL
-
- @Stable
- override val isWarning: Boolean
- get() = state and Warning != 0UL
-
@Stable
override val isHovered: Boolean
get() = state and Hovered != 0UL
@@ -240,19 +240,17 @@ value class DropdownState(val state: ULong) : StateWithOutline {
focused: Boolean = isFocused,
pressed: Boolean = isPressed,
hovered: Boolean = isHovered,
- outline: Outline = Outline.of(isWarning, isError),
active: Boolean = isActive,
) = of(
enabled = enabled,
focused = focused,
pressed = pressed,
hovered = hovered,
- outline = outline,
- active = active
+ active = active,
)
override fun toString() =
- "${javaClass.simpleName}(isEnabled=$isEnabled, isFocused=$isFocused, isError=$isError, isWarning=$isWarning, " +
+ "${javaClass.simpleName}(isEnabled=$isEnabled, isFocused=$isFocused, " +
"isHovered=$isHovered, isPressed=$isPressed, isActive=$isActive)"
companion object {
@@ -262,7 +260,6 @@ value class DropdownState(val state: ULong) : StateWithOutline {
focused: Boolean = false,
pressed: Boolean = false,
hovered: Boolean = false,
- outline: Outline = Outline.None,
active: Boolean = false,
) = DropdownState(
if (enabled) {
@@ -272,10 +269,8 @@ value class DropdownState(val state: ULong) : StateWithOutline {
(if (focused) Focused else 0UL) or
(if (pressed) Pressed else 0UL) or
(if (hovered) Hovered else 0UL) or
- (if (outline == Outline.Error) Error else 0UL) or
- (if (outline == Outline.Warning) Warning else 0UL) or
(if (active) Active else 0UL)
- }
+ },
)
}
}
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/ExperimentalJewelApi.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ExperimentalJewelApi.kt
similarity index 83%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/ExperimentalJewelApi.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ExperimentalJewelApi.kt
index 94be5e4772b8..0f09513b8819 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/ExperimentalJewelApi.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ExperimentalJewelApi.kt
@@ -3,10 +3,10 @@ package org.jetbrains.jewel
@RequiresOptIn(
level = RequiresOptIn.Level.WARNING,
message = "This is an experimental API for Jewel and is likely to change before becoming " +
- "stable."
+ "stable.",
)
@Target(
AnnotationTarget.CLASS,
- AnnotationTarget.FUNCTION
+ AnnotationTarget.FUNCTION,
)
annotation class ExperimentalJewelApi
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalColors.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalColors.kt
index 50484450bfec..284be2cbe3b9 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalColors.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalColors.kt
@@ -8,41 +8,33 @@ import androidx.compose.ui.graphics.Color
interface GlobalColors {
val borders: BorderColors
+
val outlines: OutlineColors
- @SwingLafKey("*.infoForeground")
val infoContent: Color
}
@Immutable
interface BorderColors {
- @SwingLafKey("Component.borderColor")
val normal: Color
- @SwingLafKey("Component.focusedBorderColor")
val focused: Color
- @SwingLafKey("*.disabledBorderColor")
val disabled: Color
}
@Immutable
interface OutlineColors {
- @SwingLafKey("*.focusColor")
val focused: Color
- @SwingLafKey("Component.warningFocusColor")
val focusedWarning: Color
- @SwingLafKey("Component.errorFocusColor")
val focusedError: Color
- @SwingLafKey("Component.inactiveWarningFocusColor")
val warning: Color
- @SwingLafKey("Component.inactiveErrorFocusColor")
val error: Color
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalMetrics.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalMetrics.kt
index fdbe4f82eeb0..684ae7a55061 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalMetrics.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GlobalMetrics.kt
@@ -1,6 +1,5 @@
package org.jetbrains.jewel
-import androidx.compose.foundation.shape.CornerSize
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.unit.Dp
@@ -9,7 +8,6 @@ import androidx.compose.ui.unit.Dp
interface GlobalMetrics {
val outlineWidth: Dp
- val outlineCornerSize: CornerSize
}
val LocalGlobalMetrics = staticCompositionLocalOf {
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GroupHeader.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GroupHeader.kt
index fb3cbd18e3be..cd3486e5a373 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GroupHeader.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/GroupHeader.kt
@@ -15,7 +15,7 @@ fun GroupHeader(
style: GroupHeaderStyle = LocalGroupHeaderStyle.current,
) {
CompositionLocalProvider(
- LocalContentColor provides style.colors.content
+ LocalContentColor provides style.colors.content,
) {
Row(modifier, verticalAlignment = Alignment.CenterVertically) {
Text(text)
@@ -23,7 +23,7 @@ fun GroupHeader(
color = style.colors.divider,
orientation = Orientation.Horizontal,
startIndent = style.metrics.indent,
- thickness = style.metrics.dividerThickness
+ thickness = style.metrics.dividerThickness,
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Icon.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Icon.kt
index e4434dd12450..8208ab47dd7d 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Icon.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Icon.kt
@@ -7,13 +7,13 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
-import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.paint
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.toolingGraphicsLayer
@@ -32,7 +32,6 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import org.xml.sax.InputSource
import java.io.InputStream
-import java.util.jar.JarFile
/**
* Icon component that draws [imageVector] using [tint], defaulting to
@@ -58,7 +57,7 @@ fun Icon(
painter = rememberVectorPainter(imageVector),
contentDescription = contentDescription,
modifier = modifier,
- tint = tint
+ tint = tint,
)
}
@@ -87,7 +86,7 @@ fun Icon(
painter = painter,
contentDescription = contentDescription,
modifier = modifier,
- tint = tint
+ tint = tint,
)
}
@@ -95,15 +94,15 @@ fun Icon(
fun Icon(
resource: String,
contentDescription: String?,
- resourceLoader: ResourceLoader = LocalResourceLoader.current,
modifier: Modifier = Modifier,
+ resourceLoader: ResourceLoader = LocalResourceLoader.current,
tint: Color = Color.Unspecified,
) {
Icon(
painter = painterResource(resource, resourceLoader),
contentDescription = contentDescription,
modifier = modifier,
- tint = tint
+ tint = tint,
)
}
@@ -123,11 +122,32 @@ fun Icon(
@Composable
fun Icon(
painter: Painter,
- contentDescription: String? = null,
+ contentDescription: String?,
modifier: Modifier = Modifier,
tint: Color = Color.Unspecified,
) {
- val colorFilter = if (tint == Color.Unspecified) null else ColorFilter.tint(tint)
+ val colorFilter = if (tint.isSpecified) ColorFilter.tint(tint) else null
+ Icon(painter, contentDescription, colorFilter, modifier)
+}
+
+/**
+ * Icon component that draws a [painter] using a [colorFilter]
+ *
+ * @param painter [Painter] to draw inside this Icon
+ * @param contentDescription text used by accessibility services to
+ * describe what this icon represents. This should always be
+ * provided unless this icon is used for decorative purposes, and
+ * does not represent a meaningful action that a user can take.
+ * @param modifier optional [Modifier] for this Icon
+ * @param colorFilter color filter to be applied to [painter]
+ */
+@Composable
+fun Icon(
+ painter: Painter,
+ contentDescription: String?,
+ colorFilter: ColorFilter?,
+ modifier: Modifier = Modifier,
+) {
val semantics = if (contentDescription != null) {
Modifier.semantics {
this.contentDescription = contentDescription
@@ -142,9 +162,9 @@ fun Icon(
.paint(
painter,
colorFilter = colorFilter,
- contentScale = ContentScale.Fit
+ contentScale = ContentScale.Fit,
)
- .then(semantics)
+ .then(semantics),
)
}
@@ -202,47 +222,16 @@ private inline fun useResource(
block: (InputStream) -> T,
): T = loader.load(resourcePath).use(block)
-val LocalResourceLoader = staticCompositionLocalOf {
- ResourceLoader.Default
-}
-
private fun Modifier.defaultSizeFor(painter: Painter) =
- this.then(
+ then(
if (painter.intrinsicSize == Size.Unspecified || painter.intrinsicSize.isInfinite()) {
DefaultIconSizeModifier
} else {
Modifier
- }
+ },
)
private fun Size.isInfinite() = width.isInfinite() && height.isInfinite()
// Default icon size, for icons with no intrinsic size information
private val DefaultIconSizeModifier = Modifier.size(16.dp)
-
-fun getJarPath(klass: Class<*>): String? {
- val className = klass.name.replace('.', '/') + ".class"
- val classPath = klass.classLoader.getResource(className)?.toString() ?: return null
- if (!classPath.startsWith("jar")) {
- // Class not from a JAR
- return null
- }
- return classPath.substringBefore("!").removePrefix("jar:file:")
-}
-
-fun extractFileFromJar(jarPath: String, filePath: String) =
- JarFile(jarPath).use { jar ->
- jar.getEntry(filePath)?.let { entry ->
- jar.getInputStream(entry).use { it.readBytes().inputStream() }
- }
- }
-
-inline fun getJarPath(): String? = getJarPath(T::class.java)
-
-class RawJarResourceLoader(private val jars: List) : ResourceLoader {
-
- override fun load(resourcePath: String): InputStream =
- jars.mapNotNull { jarPath ->
- extractFileFromJar(jarPath, resourcePath)
- }.firstOrNull() ?: error("Resource $resourcePath not found in jars $jars")
-}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/InputField.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/InputField.kt
index 8f84758418ec..665e7e6f2373 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/InputField.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/InputField.kt
@@ -16,6 +16,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
@@ -33,7 +34,7 @@ internal fun InputField(
modifier: Modifier,
enabled: Boolean,
readOnly: Boolean,
- isError: Boolean,
+ outline: Outline,
undecorated: Boolean,
visualTransformation: VisualTransformation,
keyboardOptions: KeyboardOptions,
@@ -47,16 +48,15 @@ internal fun InputField(
decorationBox: @Composable (innerTextField: @Composable () -> Unit, state: InputFieldState) -> Unit,
) {
var inputState by remember(interactionSource) {
- mutableStateOf(InputFieldState.of(enabled = enabled, error = isError))
+ mutableStateOf(InputFieldState.of(enabled = enabled))
}
- remember(isError, enabled) {
- inputState = inputState.copy(error = isError, enabled = enabled)
+ remember(enabled) {
+ inputState = inputState.copy(enabled = enabled)
}
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect { interaction ->
when (interaction) {
is FocusInteraction.Focus -> inputState = inputState.copy(focused = true)
-
is FocusInteraction.Unfocus -> inputState = inputState.copy(focused = false)
}
}
@@ -73,26 +73,28 @@ internal fun InputField(
val borderColor by style.colors.borderFor(inputState)
val borderModifier = Modifier.appendIf(!undecorated && borderColor.isSpecified) {
Modifier.border(
- alignment = Stroke.Alignment.Outside,
+ alignment = Stroke.Alignment.Center,
width = style.metrics.borderWidth,
color = borderColor,
- shape = shape
+ shape = shape,
)
}
val contentColor by colors.contentFor(inputState)
val mergedTextStyle = style.textStyle.merge(textStyle).copy(color = contentColor)
- val cursorBrush by colors.cursorFor(inputState)
+ val caretColor by colors.caretFor(inputState)
BasicTextField(
value = value,
modifier = modifier.then(backgroundModifier)
- .then(borderModifier),
+ .then(borderModifier)
+ .focusOutline(inputState, shape)
+ .outline(inputState, outline, shape),
onValueChange = onValueChange,
enabled = enabled,
readOnly = readOnly,
textStyle = mergedTextStyle,
- cursorBrush = cursorBrush,
+ cursorBrush = SolidColor(caretColor),
visualTransformation = visualTransformation,
onTextLayout = onTextLayout,
keyboardOptions = keyboardOptions,
@@ -102,13 +104,13 @@ internal fun InputField(
maxLines = maxLines,
decorationBox = @Composable { innerTextField: @Composable () -> Unit ->
decorationBox(innerTextField, inputState)
- }
+ },
)
}
@Immutable
@JvmInline
-value class InputFieldState(val state: ULong) : StateWithOutline {
+value class InputFieldState(val state: ULong) : FocusableComponentState {
@Stable
override val isActive: Boolean
@@ -122,14 +124,6 @@ value class InputFieldState(val state: ULong) : StateWithOutline {
override val isFocused: Boolean
get() = state and CommonStateBitMask.Focused != 0UL
- @Stable
- override val isError: Boolean
- get() = state and CommonStateBitMask.Error != 0UL
-
- @Stable
- override val isWarning: Boolean
- get() = state and CommonStateBitMask.Warning != 0UL
-
@Stable
override val isHovered: Boolean
get() = state and CommonStateBitMask.Hovered != 0UL
@@ -141,23 +135,19 @@ value class InputFieldState(val state: ULong) : StateWithOutline {
fun copy(
enabled: Boolean = isEnabled,
focused: Boolean = isFocused,
- error: Boolean = isError,
pressed: Boolean = isPressed,
hovered: Boolean = isHovered,
- warning: Boolean = isWarning,
active: Boolean = isActive,
) = of(
enabled = enabled,
focused = focused,
- error = error,
pressed = pressed,
hovered = hovered,
- warning = warning,
- active = active
+ active = active,
)
override fun toString() =
- "${javaClass.simpleName}(isEnabled=$isEnabled, isFocused=$isFocused, isError=$isError, isWarning=$isWarning, " +
+ "${javaClass.simpleName}(isEnabled=$isEnabled, isFocused=$isFocused, " +
"isHovered=$isHovered, isPressed=$isPressed, isActive=$isActive)"
companion object {
@@ -165,19 +155,15 @@ value class InputFieldState(val state: ULong) : StateWithOutline {
fun of(
enabled: Boolean = true,
focused: Boolean = false,
- error: Boolean = false,
pressed: Boolean = false,
hovered: Boolean = false,
- warning: Boolean = false,
active: Boolean = false,
) = InputFieldState(
state = (if (enabled) CommonStateBitMask.Enabled else 0UL) or
(if (focused) CommonStateBitMask.Focused else 0UL) or
- (if (error) CommonStateBitMask.Error else 0UL) or
(if (hovered) CommonStateBitMask.Hovered else 0UL) or
(if (pressed) CommonStateBitMask.Pressed else 0UL) or
- (if (warning) CommonStateBitMask.Warning else 0UL) or
- (if (active) CommonStateBitMask.Active else 0UL)
+ (if (active) CommonStateBitMask.Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJComponentStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJComponentStyling.kt
index 06a05a0e0f29..ac4cbde9db42 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJComponentStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJComponentStyling.kt
@@ -19,23 +19,23 @@ import org.jetbrains.jewel.styling.TextFieldStyle
@Stable
class IntelliJComponentStyling(
- val defaultButtonStyle: ButtonStyle,
- val outlinedButtonStyle: ButtonStyle,
val checkboxStyle: CheckboxStyle,
val chipStyle: ChipStyle,
+ val defaultButtonStyle: ButtonStyle,
+ val defaultTabStyle: TabStyle,
val dropdownStyle: DropdownStyle,
+ val editorTabStyle: TabStyle,
val groupHeaderStyle: GroupHeaderStyle,
+ val horizontalProgressBarStyle: HorizontalProgressBarStyle,
val labelledTextFieldStyle: LabelledTextFieldStyle,
+ val lazyTreeStyle: LazyTreeStyle,
val linkStyle: LinkStyle,
val menuStyle: MenuStyle,
- val horizontalProgressBarStyle: HorizontalProgressBarStyle,
+ val outlinedButtonStyle: ButtonStyle,
val radioButtonStyle: RadioButtonStyle,
val scrollbarStyle: ScrollbarStyle,
val textAreaStyle: TextAreaStyle,
val textFieldStyle: TextFieldStyle,
- val lazyTreeStyle: LazyTreeStyle,
- val defaultTabStyle: TabStyle,
- val editorTabStyle: TabStyle,
) {
override fun equals(other: Any?): Boolean {
@@ -85,4 +85,13 @@ class IntelliJComponentStyling(
result = 31 * result + editorTabStyle.hashCode()
return result
}
+
+ override fun toString(): String =
+ "IntelliJComponentStyling(checkboxStyle=$checkboxStyle, chipStyle=$chipStyle, " +
+ "defaultButtonStyle=$defaultButtonStyle, defaultTabStyle=$defaultTabStyle, dropdownStyle=$dropdownStyle, " +
+ "editorTabStyle=$editorTabStyle, groupHeaderStyle=$groupHeaderStyle, " +
+ "horizontalProgressBarStyle=$horizontalProgressBarStyle, labelledTextFieldStyle=$labelledTextFieldStyle, " +
+ "lazyTreeStyle=$lazyTreeStyle, linkStyle=$linkStyle, menuStyle=$menuStyle, " +
+ "outlinedButtonStyle=$outlinedButtonStyle, radioButtonStyle=$radioButtonStyle, " +
+ "scrollbarStyle=$scrollbarStyle, textAreaStyle=$textAreaStyle, textFieldStyle=$textFieldStyle)"
}
diff --git a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntelliJSvgLoader.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJSvgLoader.kt
similarity index 81%
rename from platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntelliJSvgLoader.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJSvgLoader.kt
index 116ec2ee62ad..bde9c8e66fac 100644
--- a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntelliJSvgLoader.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJSvgLoader.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.jewel.themes.intui.core
+package org.jetbrains.jewel
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
@@ -7,8 +7,6 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.ResourceLoader
import androidx.compose.ui.res.loadSvgPainter
-import org.jetbrains.jewel.SvgLoader
-import org.jetbrains.jewel.SvgPatcher
import java.io.InputStream
import java.util.concurrent.ConcurrentHashMap
@@ -39,22 +37,23 @@ class IntelliJSvgLoader(private val svgPatcher: SvgPatcher) : SvgLoader {
): Painter {
val density = LocalDensity.current
- val painter = try {
- useResource(resourcePath, loader) {
- loadSvgPainter(it.patchColors(), density)
+ val painter =
+ try {
+ useResource(resourcePath, loader) {
+ loadSvgPainter(it.patchColors(), density)
+ }
+ } catch (e: IllegalArgumentException) {
+ val simplerPath = trySimplifyingPath(resourcePath)
+ if (simplerPath != null) {
+ System.err.println("Unable to load '$resourcePath' (base: $basePath), trying simpler version: $simplerPath")
+ return rememberPatchedSvgResource(basePath, simplerPath, loader)
+ } else {
+ throw IllegalArgumentException(
+ "Unable to load '$resourcePath' (base: $basePath), no simpler version available",
+ e,
+ )
+ }
}
- } catch (e: IllegalArgumentException) {
- val simplerPath = trySimplifyingPath(resourcePath)
- if (simplerPath != null) {
- System.err.println("Unable to load '$resourcePath' (base: $basePath), trying simpler version: $simplerPath")
- rememberPatchedSvgResource(basePath, simplerPath, loader)
- } else {
- throw IllegalArgumentException(
- "Unable to load '$resourcePath' (base: $basePath), no simpler version available",
- e
- )
- }
- }
return remember(resourcePath, density, loader) { painter }
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJTheme.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJTheme.kt
index 9abb85ac463f..6c26b6eacd21 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJTheme.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJTheme.kt
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import org.jetbrains.jewel.styling.ButtonStyle
import org.jetbrains.jewel.styling.CheckboxStyle
@@ -61,6 +62,11 @@ interface IntelliJTheme {
@ReadOnlyComposable
get() = LocalTextStyle.current
+ val contentColor: Color
+ @Composable
+ @ReadOnlyComposable
+ get() = LocalContentColor.current
+
val isDark: Boolean
@Composable
@ReadOnlyComposable
@@ -172,7 +178,6 @@ interface IntelliJTheme {
}
}
-@ExperimentalJewelApi
@Composable
fun IntelliJTheme(
theme: IntelliJThemeDefinition,
@@ -186,13 +191,15 @@ fun IntelliJTheme(
@Composable
fun IntelliJTheme(theme: IntelliJThemeDefinition, content: @Composable () -> Unit) {
+ val defaultTextStyle = theme.defaultTextStyle
+
CompositionLocalProvider(
- LocalContentColor provides theme.defaultTextStyle.color,
LocalIsDarkTheme provides theme.isDark,
- LocalTextStyle provides theme.defaultTextStyle,
+ LocalContentColor provides defaultTextStyle.color,
+ LocalTextStyle provides defaultTextStyle,
LocalGlobalColors provides theme.globalColors,
- LocalGlobalMetrics provides theme.metrics,
- content = content
+ LocalGlobalMetrics provides theme.globalMetrics,
+ content = content,
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeColorPalette.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeColorPalette.kt
index e0252e24e0c7..7f13cb4352be 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeColorPalette.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeColorPalette.kt
@@ -1,12 +1,16 @@
package org.jetbrains.jewel
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color
+@Stable
interface IntelliJThemeColorPalette {
fun lookup(colorKey: String): Color?
}
+@Immutable
object EmptyThemeColorPalette : IntelliJThemeColorPalette {
override fun lookup(colorKey: String): Color? = null
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeDefinition.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeDefinition.kt
index 072cb3c9926b..605a6b54f348 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeDefinition.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeDefinition.kt
@@ -8,7 +8,7 @@ interface IntelliJThemeDefinition {
val isDark: Boolean
val globalColors: GlobalColors
- val metrics: GlobalMetrics
+ val globalMetrics: GlobalMetrics
val defaultTextStyle: TextStyle
val colorPalette: IntelliJThemeColorPalette
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeIconData.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeIconData.kt
index c1d99a1e95f5..e70ca30c735d 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeIconData.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/IntelliJThemeIconData.kt
@@ -1,11 +1,15 @@
package org.jetbrains.jewel
+import androidx.compose.runtime.Immutable
+
+@Immutable
interface IntelliJThemeIconData {
val iconOverrides: Map
val colorPalette: Map
}
+@Immutable
object EmptyThemeIconData : IntelliJThemeIconData {
override val iconOverrides: Map = emptyMap()
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/JewelResourceLoader.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/JewelResourceLoader.kt
new file mode 100644
index 000000000000..0fc3782dbca0
--- /dev/null
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/JewelResourceLoader.kt
@@ -0,0 +1,6 @@
+package org.jetbrains.jewel
+
+interface JewelResourceLoader {
+
+ val searchClasses: List>
+}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LabelledTextField.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LabelledTextField.kt
index 7ccedf96d0f8..05a1937fd14c 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LabelledTextField.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LabelledTextField.kt
@@ -21,16 +21,23 @@ import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.offset
import org.jetbrains.jewel.styling.LabelledTextFieldStyle
+/**
+ * @param placeholder the optional placeholder to be displayed over the component when
+ * the [value] is empty.
+ * @param hint the optional hint to be displayed underneath the component. By default it
+ * will have a greyed out appearance and smaller text.
+ * @param label the label to display above the component.
+ */
@Composable
fun LabelledTextField(
- label: @Composable () -> Unit,
value: String,
onValueChange: (String) -> Unit,
+ label: @Composable () -> Unit,
modifier: Modifier = Modifier,
textFieldModifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
- isError: Boolean = false,
+ outline: Outline = Outline.None,
hint: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
@@ -61,7 +68,7 @@ fun LabelledTextField(
textFieldModifier = textFieldModifier,
enabled = enabled,
readOnly = readOnly,
- isError = isError,
+ outline = outline,
hint = hint,
placeholder = placeholder,
trailingIcon = trailingIcon,
@@ -72,10 +79,17 @@ fun LabelledTextField(
onTextLayout = onTextLayout,
style = style,
textStyle = textStyle,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
)
}
+/**
+ * @param placeholder the optional placeholder to be displayed over the component when
+ * the [value] is empty.
+ * @param hint the optional hint to be displayed underneath the component. By default it
+ * will have a greyed out appearance and smaller text.
+ * @param label the label to display above the component.
+ */
@Composable
fun LabelledTextField(
label: @Composable () -> Unit,
@@ -85,7 +99,7 @@ fun LabelledTextField(
textFieldModifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
- isError: Boolean = false,
+ outline: Outline = Outline.None,
hint: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
@@ -104,7 +118,7 @@ fun LabelledTextField(
CompositionLocalProvider(
LocalTextStyle provides style.textStyles.label,
LocalContentColor provides style.colors.label,
- content = label
+ content = label,
)
},
textField = {
@@ -114,7 +128,7 @@ fun LabelledTextField(
modifier = textFieldModifier,
enabled = enabled,
readOnly = readOnly,
- isError = isError,
+ outline = outline,
placeholder = placeholder,
trailingIcon = trailingIcon,
undecorated = undecorated,
@@ -124,7 +138,7 @@ fun LabelledTextField(
onTextLayout = onTextLayout,
style = style,
textStyle = textStyle,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
)
},
hint = hint?.let {
@@ -132,11 +146,11 @@ fun LabelledTextField(
CompositionLocalProvider(
LocalTextStyle provides style.textStyles.hint,
LocalContentColor provides style.colors.hint,
- content = it
+ content = it,
)
}
},
- style = style
+ style = style,
)
}
@@ -164,7 +178,7 @@ private fun LabelledTextFieldLayout(
hint()
}
}
- }
+ },
) { measurables, incomingConstraints ->
val hintMeasurable = measurables.firstOrNull { it.layoutId == HINT_ID }
@@ -173,7 +187,7 @@ private fun LabelledTextFieldLayout(
val constraintsWithoutSpacing = incomingConstraints.offset(
horizontal = -horizontalSpacing,
- vertical = -verticalSpacing
+ vertical = -verticalSpacing,
)
val textFieldPlaceable = measurables.first { it.layoutId == TEXT_FIELD_ID }
@@ -185,7 +199,7 @@ private fun LabelledTextFieldLayout(
val hintPlaceable = hintMeasurable?.measure(
constraintsWithoutSpacing
.offset(vertical = -textFieldPlaceable.height)
- .copy(maxWidth = textFieldPlaceable.width)
+ .copy(maxWidth = textFieldPlaceable.width),
)
val width = labelPlaceable.width + textFieldPlaceable.width + horizontalSpacing
@@ -194,15 +208,15 @@ private fun LabelledTextFieldLayout(
layout(width, height) {
labelPlaceable.placeRelative(
x = 0,
- y = Alignment.CenterVertically.align(labelPlaceable.height, textFieldPlaceable.height)
+ y = Alignment.CenterVertically.align(labelPlaceable.height, textFieldPlaceable.height),
)
textFieldPlaceable.placeRelative(
x = labelPlaceable.width + horizontalSpacing,
- y = 0
+ y = 0,
)
hintPlaceable?.placeRelative(
x = labelPlaceable.width + horizontalSpacing,
- y = textFieldPlaceable.height + verticalSpacing
+ y = textFieldPlaceable.height + verticalSpacing,
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LazyTree.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LazyTree.kt
index 376c2c9d3ebe..caba4a0764ec 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LazyTree.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LazyTree.kt
@@ -1,12 +1,11 @@
package org.jetbrains.jewel
import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.res.ResourceLoader
import org.jetbrains.jewel.foundation.lazy.SelectableLazyItemScope
@@ -52,14 +51,10 @@ fun LazyTree(
onElementDoubleClick = onElementDoubleClick,
interactionSource = interactionSource,
keyActions = keyActions,
- chevronContent = { state ->
- Box(Modifier.rotate(if (state.isExpanded) 90f else 0f)) {
- Icon(
- painter = painterResource(style.icons.nodeChevron, resourceLoader),
- contentDescription = "Dropdown link",
- tint = colors.chevronTintFor(state).value
- )
- }
+ chevronContent = { elementState ->
+ val painterProvider = style.icons.nodeChevron(elementState.isExpanded)
+ val painter by painterProvider.getPainter(elementState, resourceLoader)
+ Icon(painter = painter, contentDescription = null)
},
nodeContent = {
CompositionLocalProvider(
@@ -68,12 +63,12 @@ fun LazyTree(
TreeElementState.of(
isFocused,
isSelected,
- false
- )
+ false,
+ ),
).value
.takeOrElse { LocalContentColor.current }
- )
+ ),
) { nodeContent(it) }
- }
+ },
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LinearProgressBar.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LinearProgressBar.kt
index dae271e9c8ae..2774f68a4c2b 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LinearProgressBar.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/LinearProgressBar.kt
@@ -24,6 +24,8 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import org.jetbrains.jewel.styling.HorizontalProgressBarStyle
+// TODO implement green/red/yellow variants based on com.intellij.openapi.progress.util.ColorProgressBar
+
@Composable
fun HorizontalProgressBar(
progress: Float, // from 0 to 1
@@ -48,9 +50,9 @@ fun HorizontalProgressBar(
color = colors.progress,
topLeft = Offset(progressX, 0f),
size = size.copy(width = progressWidth),
- cornerRadius = cornerRadius
+ cornerRadius = cornerRadius,
)
- }
+ },
)
}
@@ -67,13 +69,13 @@ fun IndeterminateHorizontalProgressBar(
targetValue = 2f,
animationSpec = infiniteRepeatable(
tween(durationMillis = cycleDurationMillis, easing = LinearEasing),
- repeatMode = RepeatMode.Restart
- )
+ repeatMode = RepeatMode.Restart,
+ ),
)
val highlightWidth = style.metrics.indeterminateHighlightWidth
val colors = style.colors
- val colorsList by remember { mutableStateOf(listOf(colors.progress, colors.indeterminateHighlight)) }
+ val colorsList by remember { mutableStateOf(listOf(colors.indeterminateBase, colors.indeterminateHighlight)) }
val shape = RoundedCornerShape(style.metrics.cornerSize)
Box(
@@ -90,9 +92,9 @@ fun IndeterminateHorizontalProgressBar(
colors = colorsList,
start = Offset(x, 0f),
end = Offset(x + highlightWidth.value, 0f),
- TileMode.Mirror
- )
+ TileMode.Mirror,
+ ),
)
- }
+ },
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Link.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Link.kt
index 840d125523f7..5cb1a3ee9d76 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Link.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Link.kt
@@ -22,6 +22,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.InputMode
import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.res.ResourceLoader
@@ -85,7 +86,7 @@ fun Link(
indication = indication,
style = style,
resourceLoader = resourceLoader,
- icon = null
+ icon = null,
)
}
@@ -125,7 +126,7 @@ fun ExternalLink(
indication = indication,
style = style,
resourceLoader = resourceLoader,
- icon = style.icons.externalLink
+ icon = style.icons.externalLink,
)
}
@@ -156,7 +157,7 @@ fun DropdownLink(
Box(
Modifier.onHover {
hovered = it
- }
+ },
) {
LinkImpl(
text = text,
@@ -180,7 +181,7 @@ fun DropdownLink(
indication = indication,
style = style,
icon = style.icons.dropdownChevron,
- resourceLoader = resourceLoader
+ resourceLoader = resourceLoader,
)
if (expanded) {
@@ -195,7 +196,8 @@ fun DropdownLink(
modifier = menuModifier,
style = menuStyle,
horizontalAlignment = Alignment.Start, // TODO no idea what goes here
- content = menuContent
+ content = menuContent,
+ resourceLoader = resourceLoader,
)
}
}
@@ -262,8 +264,8 @@ private fun LinkImpl(
lineHeight = lineHeight,
fontFamily = fontFamily,
fontStyle = fontStyle,
- letterSpacing = letterSpacing
- )
+ letterSpacing = letterSpacing,
+ ),
)
val clickable = Modifier.clickable(
@@ -274,28 +276,28 @@ private fun LinkImpl(
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
- indication = indication
+ indication = indication,
)
val focusHaloModifier = Modifier.border(
alignment = Stroke.Alignment.Outside,
width = LocalGlobalMetrics.current.outlineWidth,
color = LocalGlobalColors.current.outlines.focused,
- shape = RoundedCornerShape(style.metrics.focusHaloCornerSize)
+ shape = RoundedCornerShape(style.metrics.focusHaloCornerSize),
)
Row(
modifier = modifier.then(clickable)
.appendIf(linkState.isFocused) { focusHaloModifier },
horizontalArrangement = Arrangement.spacedBy(style.metrics.textIconGap),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
BasicText(
text = text,
style = mergedStyle,
overflow = overflow,
softWrap = true,
- maxLines = 1
+ maxLines = 1,
)
if (icon != null) {
@@ -304,7 +306,7 @@ private fun LinkImpl(
iconPainter,
contentDescription = null,
modifier = Modifier.size(style.metrics.iconSize),
- tint = style.colors.iconTint
+ colorFilter = if (!linkState.isEnabled) ColorFilter.disabled() else null,
)
}
}
@@ -355,7 +357,7 @@ value class LinkState(val state: ULong) : FocusableComponentState {
visited = visited,
pressed = pressed,
hovered = hovered,
- active = active
+ active = active,
)
@Composable
@@ -397,7 +399,7 @@ value class LinkState(val state: ULong) : FocusableComponentState {
(if (focused) Focused else 0UL) or
(if (pressed) Pressed else 0UL) or
(if (hovered) Hovered else 0UL) or
- (if (active) Active else 0UL)
+ (if (active) Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Menu.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Menu.kt
index 1358459b5542..a7fa869e1fc6 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Menu.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Menu.kt
@@ -10,10 +10,12 @@ import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.rememberScrollbarAdapter
@@ -31,13 +33,17 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.InputMode
import androidx.compose.ui.input.InputModeManager
import androidx.compose.ui.input.key.Key
@@ -48,18 +54,24 @@ import androidx.compose.ui.input.key.type
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalInputModeManager
-import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.ResourceLoader
import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupProperties
import org.jetbrains.jewel.CommonStateBitMask.Active
import org.jetbrains.jewel.foundation.Stroke
import org.jetbrains.jewel.foundation.border
import org.jetbrains.jewel.foundation.onHover
+import org.jetbrains.jewel.styling.MenuItemColors
+import org.jetbrains.jewel.styling.MenuItemMetrics
import org.jetbrains.jewel.styling.MenuStyle
@Composable
internal fun MenuContent(
+ resourceLoader: ResourceLoader,
modifier: Modifier = Modifier,
style: MenuStyle = IntelliJTheme.menuStyle,
content: MenuScope.() -> Unit,
@@ -80,28 +92,28 @@ internal fun MenuContent(
elevation = style.metrics.shadowSize,
shape = menuShape,
ambientColor = colors.shadow,
- spotColor = colors.shadow
+ spotColor = colors.shadow,
)
.border(Stroke.Alignment.Center, style.metrics.borderWidth, colors.border, menuShape)
.background(colors.background, menuShape)
.width(IntrinsicSize.Max)
.onHover {
localMenuManager.onHoveredChange(it)
- }
+ },
) {
Column(
modifier = Modifier
.verticalScroll(scrollState)
- .padding(style.metrics.contentPadding)
+ .padding(style.metrics.contentPadding),
) {
items.forEach {
when (it) {
is MenuSelectableItem -> {
- MenuSelectableItem(
+ MenuItem(
selected = it.isSelected,
onClick = it.onClick,
enabled = it.isEnabled,
- content = it.content
+ content = it.content,
)
}
@@ -109,7 +121,8 @@ internal fun MenuContent(
MenuSubmenuItem(
enabled = it.isEnabled,
submenu = it.submenu,
- content = it.content
+ content = it.content,
+ resourceLoader = resourceLoader,
)
}
@@ -122,7 +135,7 @@ internal fun MenuContent(
Box(modifier = Modifier.matchParentSize()) {
VerticalScrollbar(
rememberScrollbarAdapter(scrollState),
- modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd)
+ modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd),
)
}
}
@@ -146,7 +159,7 @@ interface MenuScope {
fun passiveItem(content: @Composable () -> Unit)
}
-fun MenuScope.divider() {
+fun MenuScope.separator() {
passiveItem {
MenuSeparator()
}
@@ -193,7 +206,7 @@ private fun (MenuScope.() -> Unit).asList() = buildList {
override fun submenu(enabled: Boolean, submenu: MenuScope.() -> Unit, content: @Composable () -> Unit) {
add(SubmenuItem(enabled, submenu, content))
}
- }
+ },
)
}
@@ -222,17 +235,19 @@ private data class SubmenuItem(
@Composable
fun MenuSeparator(
modifier: Modifier = Modifier,
- style: MenuStyle = IntelliJTheme.menuStyle,
+ metrics: MenuItemMetrics = IntelliJTheme.menuStyle.metrics.itemMetrics,
+ colors: MenuItemColors = IntelliJTheme.menuStyle.colors.itemColors,
) {
Divider(
- modifier = modifier.padding(style.metrics.itemMetrics.separatorPadding),
+ modifier = modifier.padding(metrics.separatorPadding),
+ thickness = metrics.separatorThickness,
orientation = Orientation.Horizontal,
- color = style.colors.itemColors.separator
+ color = colors.separator,
)
}
@Composable
-fun MenuSelectableItem(
+fun MenuItem(
selected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
@@ -283,9 +298,9 @@ fun MenuSelectableItem(
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
- indication = null
+ indication = null,
)
- .fillMaxWidth()
+ .fillMaxWidth(),
) {
DisposableEffect(Unit) {
if (selected) {
@@ -295,20 +310,19 @@ fun MenuSelectableItem(
onDispose { }
}
- val colors = style.colors.itemColors
- val metrics = style.metrics
- val shape = RoundedCornerShape(metrics.itemMetrics.cornerSize)
+ val itemColors = style.colors.itemColors
+ val itemMetrics = style.metrics.itemMetrics
CompositionLocalProvider(
- LocalContentColor provides colors.contentFor(itemState).value
+ LocalContentColor provides itemColors.contentFor(itemState).value,
) {
- Row(
+ val backgroundColor by itemColors.backgroundFor(itemState)
+
+ Box(
Modifier
- .padding(metrics.itemMetrics.padding)
- .background(colors.backgroundFor(itemState).value, shape)
.fillMaxWidth()
- .padding(metrics.itemMetrics.contentPadding),
- verticalAlignment = Alignment.CenterVertically
+ .drawItemBackground(itemMetrics, backgroundColor)
+ .padding(itemMetrics.contentPadding),
) {
content()
}
@@ -318,6 +332,7 @@ fun MenuSelectableItem(
@Composable
fun MenuSubmenuItem(
+ resourceLoader: ResourceLoader,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@@ -352,8 +367,14 @@ fun MenuSubmenuItem(
}
}
+ val itemColors = style.colors.itemColors
+ val menuMetrics = style.metrics
+
+ val backgroundColor by itemColors.backgroundFor(itemState)
Box(
modifier = modifier
+ .fillMaxWidth()
+ .drawItemBackground(menuMetrics.itemMetrics, backgroundColor)
.focusRequester(focusRequester)
.clickable(
onClick = {
@@ -362,7 +383,7 @@ fun MenuSubmenuItem(
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
- indication = null
+ indication = null,
)
.onKeyEvent {
if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionRight) {
@@ -371,34 +392,27 @@ fun MenuSubmenuItem(
} else {
false
}
- }
- .fillMaxWidth()
+ },
) {
- val colors = style.colors.itemColors
- val metrics = style.metrics
- val shape = RoundedCornerShape(metrics.itemMetrics.cornerSize)
-
CompositionLocalProvider(
- LocalContentColor provides colors.contentFor(itemState).value
+ LocalContentColor provides itemColors.contentFor(itemState).value,
) {
Row(
- Modifier
- .padding(metrics.itemMetrics.padding)
- .background(colors.backgroundFor(itemState).value, shape)
- .fillMaxWidth()
- .padding(metrics.submenuMetrics.itemPadding),
- verticalAlignment = Alignment.CenterVertically
+ Modifier.fillMaxWidth()
+ .padding(menuMetrics.itemMetrics.contentPadding),
+ verticalAlignment = Alignment.CenterVertically,
) {
Box(Modifier.weight(1f)) {
content()
}
- Box(Modifier.width(24.dp), contentAlignment = Alignment.Center) {
- Icon(
- painter = painterResource(style.icons.submenuChevron),
- tint = colors.iconTintFor(itemState).value
- )
- }
+ val chevronPainter by style.icons.submenuChevron.getPainter(itemState, resourceLoader)
+ Icon(
+ painter = chevronPainter,
+ tint = itemColors.iconTintFor(itemState).value,
+ contentDescription = null,
+ modifier = Modifier.size(16.dp),
+ )
}
}
@@ -413,14 +427,42 @@ fun MenuSubmenuItem(
}
},
style = style,
- content = submenu
+ content = submenu,
+ resourceLoader = resourceLoader,
)
}
}
}
+private fun Modifier.drawItemBackground(itemMetrics: MenuItemMetrics, backgroundColor: Color) =
+ drawBehind {
+ val cornerSizePx = itemMetrics.selectionCornerSize.toPx(size, density = this)
+ val cornerRadius = CornerRadius(cornerSizePx, cornerSizePx)
+
+ val outerPadding = itemMetrics.outerPadding
+ val offset = Offset(
+ x = outerPadding.calculateLeftPadding(layoutDirection).toPx(),
+ y = outerPadding.calculateTopPadding().toPx(),
+ )
+ drawRoundRect(
+ color = backgroundColor,
+ cornerRadius = cornerRadius,
+ topLeft = offset,
+ size = size.subtract(outerPadding, density = this, layoutDirection),
+ )
+ }
+
+private fun Size.subtract(paddingValues: PaddingValues, density: Density, layoutDirection: LayoutDirection): Size =
+ with(density) {
+ Size(
+ width - paddingValues.calculateLeftPadding(layoutDirection).toPx() - paddingValues.calculateRightPadding(layoutDirection).toPx(),
+ height - paddingValues.calculateTopPadding().toPx() - paddingValues.calculateBottomPadding().toPx(),
+ )
+ }
+
@Composable
internal fun Submenu(
+ resourceLoader: ResourceLoader,
onDismissRequest: (InputMode) -> Boolean,
modifier: Modifier = Modifier,
style: MenuStyle = IntelliJTheme.menuStyle,
@@ -430,9 +472,9 @@ internal fun Submenu(
val popupPositionProvider = AnchorHorizontalMenuPositionProvider(
contentOffset = style.metrics.submenuMetrics.offset,
- contentMargin = style.metrics.margin,
+ contentMargin = style.metrics.menuMargin,
alignment = Alignment.Top,
- density = density
+ density = density,
)
var focusManager: FocusManager? by mutableStateOf(null)
@@ -443,16 +485,17 @@ internal fun Submenu(
}
Popup(
- focusable = true,
+ popupPositionProvider = popupPositionProvider,
onDismissRequest = {
menuManager.closeAll(InputMode.Touch, false)
},
- popupPositionProvider = popupPositionProvider,
+ properties = PopupProperties(focusable = true),
+ onPreviewKeyEvent = { false },
onKeyEvent = {
val currentFocusManager = checkNotNull(focusManager) { "FocusManager must not be null" }
val currentInputModeManager = checkNotNull(inputModeManager) { "InputModeManager must not be null" }
handlePopupMenuOnKeyEvent(it, currentFocusManager, currentInputModeManager, menuManager)
- }
+ },
) {
focusManager = LocalFocusManager.current
inputModeManager = LocalInputModeManager.current
@@ -460,7 +503,8 @@ internal fun Submenu(
CompositionLocalProvider(LocalMenuManager provides menuManager) {
MenuContent(
modifier = modifier,
- content = content
+ content = content,
+ resourceLoader = resourceLoader,
)
}
}
@@ -535,50 +579,3 @@ value class MenuItemState(val state: ULong) : SelectableComponentState {
}
}
}
-
-class MenuManager(
- val onDismissRequest: (InputMode) -> Boolean,
- private val parentMenuManager: MenuManager? = null,
-) {
-
- private var isHovered: Boolean = false
-
- /**
- * Called when the hovered state of the menu changes.
- * This is used to abort parent menu closing in unforced mode
- * when submenu closed by click parent menu's item.
- *
- * @param hovered true if the menu is hovered, false otherwise.
- */
- internal fun onHoveredChange(hovered: Boolean) {
- isHovered = hovered
- }
-
- /**
- * Close all menus in the hierarchy.
- *
- * @param mode the input mode, menus close by pointer or keyboard event.
- * @param force true to force close all menus ignore parent hover state, false otherwise.
- */
- fun closeAll(mode: InputMode, force: Boolean) {
- // We ignore the pointer event if the menu is hovered in unforced mode.
- if (!force && mode == InputMode.Touch && isHovered) return
-
- if (onDismissRequest(mode)) {
- parentMenuManager?.closeAll(mode, force)
- }
- }
-
- fun close(mode: InputMode) = onDismissRequest(mode)
-
- fun isRootMenu(): Boolean = parentMenuManager == null
-
- fun isSubmenu(): Boolean = parentMenuManager != null
-
- fun submenuManager(onDismissRequest: (InputMode) -> Boolean) =
- MenuManager(onDismissRequest = onDismissRequest, parentMenuManager = this)
-}
-
-val LocalMenuManager = staticCompositionLocalOf {
- error("No MenuManager provided")
-}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/MenuManager.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/MenuManager.kt
new file mode 100644
index 000000000000..9798aed3990d
--- /dev/null
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/MenuManager.kt
@@ -0,0 +1,51 @@
+package org.jetbrains.jewel
+
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.input.InputMode
+
+class MenuManager(
+ val onDismissRequest: (InputMode) -> Boolean,
+ private val parentMenuManager: MenuManager? = null,
+) {
+
+ private var isHovered: Boolean = false
+
+ /**
+ * Called when the hovered state of the menu changes.
+ * This is used to abort parent menu closing in unforced mode
+ * when submenu closed by click parent menu's item.
+ *
+ * @param hovered true if the menu is hovered, false otherwise.
+ */
+ internal fun onHoveredChange(hovered: Boolean) {
+ isHovered = hovered
+ }
+
+ /**
+ * Close all menus in the hierarchy.
+ *
+ * @param mode the input mode, menus close by pointer or keyboard event.
+ * @param force true to force close all menus ignore parent hover state, false otherwise.
+ */
+ fun closeAll(mode: InputMode, force: Boolean) {
+ // We ignore the pointer event if the menu is hovered in unforced mode.
+ if (!force && mode == InputMode.Touch && isHovered) return
+
+ if (onDismissRequest(mode)) {
+ parentMenuManager?.closeAll(mode, force)
+ }
+ }
+
+ fun close(mode: InputMode) = onDismissRequest(mode)
+
+ fun isRootMenu(): Boolean = parentMenuManager == null
+
+ fun isSubmenu(): Boolean = parentMenuManager != null
+
+ fun submenuManager(onDismissRequest: (InputMode) -> Boolean) =
+ MenuManager(onDismissRequest = onDismissRequest, parentMenuManager = this)
+}
+
+val LocalMenuManager = staticCompositionLocalOf {
+ error("No MenuManager provided")
+}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Outline.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Outline.kt
index 75704658607a..71f0b21f2456 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Outline.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Outline.kt
@@ -1,6 +1,5 @@
package org.jetbrains.jewel
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
@@ -29,10 +28,10 @@ enum class Outline {
@Composable
fun Modifier.focusOutline(
state: FocusableComponentState,
- outlineShape: Shape = RoundedCornerShape(LocalGlobalMetrics.current.outlineCornerSize),
- outlineWidth: Dp = LocalGlobalMetrics.current.outlineWidth,
+ outlineShape: Shape,
+ outlineWidth: Dp = IntelliJTheme.globalMetrics.outlineWidth,
): Modifier {
- val outlineColors = LocalGlobalColors.current.outlines
+ val outlineColors = IntelliJTheme.globalColors.outlines
return thenIf(state.isFocused) {
val outlineColor = outlineColors.focused
@@ -40,34 +39,15 @@ fun Modifier.focusOutline(
}
}
-@Composable
-fun Modifier.outline(
- state: StateWithOutline,
- outlineShape: Shape = RoundedCornerShape(LocalGlobalMetrics.current.outlineCornerSize),
- outlineWidth: Dp = LocalGlobalMetrics.current.outlineWidth,
-): Modifier {
- val outlineColors = LocalGlobalColors.current.outlines
-
- return thenIf(state.hasOutline) {
- val outlineColor = when {
- state.isError -> outlineColors.focusedError
- state.isWarning -> outlineColors.focusedWarning
- state.isFocused -> outlineColors.focused
- else -> error("State $state says it has an outline, but doesn't really")
- }
- border(Stroke.Alignment.Inside, outlineWidth, outlineColor, outlineShape)
- }
-}
-
@Composable
fun Modifier.outline(
state: FocusableComponentState,
outline: Outline,
+ outlineShape: Shape,
alignment: Stroke.Alignment = Stroke.Alignment.Outside,
- outlineShape: Shape = RoundedCornerShape(LocalGlobalMetrics.current.outlineCornerSize),
- outlineWidth: Dp = LocalGlobalMetrics.current.outlineWidth,
+ outlineWidth: Dp = IntelliJTheme.globalMetrics.outlineWidth,
): Modifier {
- val outlineColors = LocalGlobalColors.current.outlines
+ val outlineColors = IntelliJTheme.globalColors.outlines
return thenIf(outline != Outline.None) {
val outlineColor = when {
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Popup.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Popup.kt
index 863ed7ce7755..9309b3f123ef 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Popup.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Popup.kt
@@ -83,7 +83,7 @@ internal data class AnchorVerticalMenuPositionProvider(
left = leftMargin,
top = topMargin,
right = windowSize.width - rightMargin,
- bottom = windowSize.height - bottomMargin
+ bottom = windowSize.height - bottomMargin,
)
// The content offset specified using the dropdown offset parameter.
@@ -136,7 +136,7 @@ internal data class AnchorHorizontalMenuPositionProvider(
left = leftMargin,
top = topMargin,
right = windowSize.width - rightMargin,
- bottom = windowSize.height - bottomMargin
+ bottom = windowSize.height - bottomMargin,
)
// The content offset specified using the dropdown offset parameter.
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/RadioButton.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/RadioButton.kt
index 08e47b8813a6..e812fd7ae070 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/RadioButton.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/RadioButton.kt
@@ -58,7 +58,7 @@ fun RadioButton(
interactionSource = interactionSource,
style = style,
textStyle = textStyle,
- content = null
+ content = null,
)
}
@@ -84,7 +84,7 @@ fun RadioButtonRow(
resourceLoader = resourceLoader,
interactionSource = interactionSource,
style = style,
- textStyle = textStyle
+ textStyle = textStyle,
) {
Text(text)
}
@@ -113,7 +113,7 @@ fun RadioButtonRow(
style = style,
textStyle = textStyle,
resourceLoader = resourceLoader,
- content = content
+ content = content,
)
}
@@ -159,7 +159,7 @@ private fun RadioButtonImpl(
enabled = enabled,
role = Role.RadioButton,
interactionSource = interactionSource,
- indication = null
+ indication = null,
)
val colors = style.colors
@@ -174,14 +174,14 @@ private fun RadioButtonImpl(
Row(
wrapperModifier,
horizontalArrangement = Arrangement.spacedBy(metrics.iconContentGap),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
RadioButtonImage(Modifier, radioButtonPainter, radioButtonModifier)
val contentColor by colors.contentFor(radioButtonState)
CompositionLocalProvider(
LocalTextStyle provides textStyle.copy(color = contentColor.takeOrElse { textStyle.color }),
- LocalContentColor provides contentColor.takeOrElse { textStyle.color }
+ LocalContentColor provides contentColor.takeOrElse { textStyle.color },
) {
content()
}
@@ -238,7 +238,7 @@ value class RadioButtonState(val state: ULong) : SelectableComponentState {
focused = focused,
pressed = pressed,
hovered = hovered,
- active = active
+ active = active,
)
override fun toString() =
@@ -264,7 +264,7 @@ value class RadioButtonState(val state: ULong) : SelectableComponentState {
(if (focused) Focused else 0UL) or
(if (pressed) Pressed else 0UL) or
(if (hovered) Hovered else 0UL) or
- (if (active) Active else 0UL)
+ (if (active) Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ResourceLoader.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ResourceLoader.kt
new file mode 100644
index 000000000000..cba4ee0ebb8d
--- /dev/null
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/ResourceLoader.kt
@@ -0,0 +1,8 @@
+package org.jetbrains.jewel
+
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.res.ResourceLoader
+
+val LocalResourceLoader = staticCompositionLocalOf {
+ ResourceLoader.Default
+}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Scrollbars.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Scrollbars.kt
index 3206581c0418..b2dd2e9930c4 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Scrollbars.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Scrollbars.kt
@@ -36,15 +36,15 @@ fun VerticalScrollbar(
shape = shape,
hoverDurationMillis = hoverDurationMillis,
unhoverColor = style.colors.thumbBackground,
- hoverColor = style.colors.thumbBackgroundHovered
- )
+ hoverColor = style.colors.thumbBackgroundHovered,
+ ),
) {
VerticalScrollbar(
adapter = adapter,
modifier = modifier.padding(style.metrics.trackPadding),
reverseLayout = reverseLayout,
style = LocalScrollbarStyle.current,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
)
}
}
@@ -67,15 +67,15 @@ fun HorizontalScrollbar(
shape = shape,
hoverDurationMillis = hoverDurationMillis,
unhoverColor = style.colors.thumbBackground,
- hoverColor = style.colors.thumbBackgroundHovered
- )
+ hoverColor = style.colors.thumbBackgroundHovered,
+ ),
) {
HorizontalScrollbar(
adapter = adapter,
modifier = modifier.padding(style.metrics.trackPadding),
reverseLayout = reverseLayout,
style = LocalScrollbarStyle.current,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
)
}
}
@@ -98,15 +98,15 @@ fun TabStripHorizontalScrollbar(
shape = shape,
hoverDurationMillis = hoverDurationMillis,
unhoverColor = style.colors.thumbBackground,
- hoverColor = style.colors.thumbBackgroundHovered
- )
+ hoverColor = style.colors.thumbBackgroundHovered,
+ ),
) {
HorizontalScrollbar(
adapter = adapter,
modifier = modifier.padding(1.dp),
reverseLayout = reverseLayout,
style = LocalScrollbarStyle.current,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/StateWithOutline.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/StateWithOutline.kt
deleted file mode 100644
index 3d37a00d5811..000000000000
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/StateWithOutline.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.jetbrains.jewel
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Stable
-
-interface StateWithOutline : FocusableComponentState {
-
- @Stable
- val isError: Boolean
-
- @Stable
- val isWarning: Boolean
-
- @Stable
- val hasOutline: Boolean
- get() = outline != Outline.None
-
- @Stable
- val outline: Outline
- get() = when {
- isError -> Outline.Error
- isWarning -> Outline.Warning
- else -> Outline.None
- }
-
- @Composable
- fun chooseValueWithOutline(
- normal: T,
- disabled: T,
- focused: T,
- pressed: T,
- hovered: T,
- warning: T,
- error: T,
- active: T,
- ): T =
- when {
- !isEnabled -> disabled
- isPressed && !IntelliJTheme.isSwingCompatMode -> pressed
- isHovered && !IntelliJTheme.isSwingCompatMode -> hovered
- isFocused -> focused
- isError -> error
- isWarning -> warning
- isActive -> active
- else -> normal
- }
-}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TabStrip.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TabStrip.kt
index b22e7516bb52..4210993d09cc 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TabStrip.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TabStrip.kt
@@ -42,7 +42,7 @@ fun TabStrip(
Box(
modifier
.focusable(true, remember { MutableInteractionSource() })
- .onHover { tabStripState = tabStripState.copy(hovered = it) }
+ .onHover { tabStripState = tabStripState.copy(hovered = it) },
) {
Row(
modifier = Modifier
@@ -52,12 +52,12 @@ fun TabStrip(
reverseDirection = ScrollableDefaults.reverseDirection(
LocalLayoutDirection.current,
Orientation.Vertical,
- false
+ false,
),
state = scrollState,
- interactionSource = remember { MutableInteractionSource() }
+ interactionSource = remember { MutableInteractionSource() },
)
- .selectableGroup()
+ .selectableGroup(),
) {
tabs.forEach {
TabImpl(isActive = tabStripState.isActive, tabData = it)
@@ -69,20 +69,20 @@ fun TabStrip(
animationSpec = tween(
durationMillis = 125,
delayMillis = 0,
- easing = LinearEasing
- )
+ easing = LinearEasing,
+ ),
),
exit = fadeOut(
animationSpec = tween(
durationMillis = 125,
delayMillis = 700,
- easing = LinearEasing
- )
- )
+ easing = LinearEasing,
+ ),
+ ),
) {
TabStripHorizontalScrollbar(
adapter = rememberScrollbarAdapter(scrollState),
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
)
}
}
@@ -208,7 +208,7 @@ value class TabStripState(val state: ULong) : FocusableComponentState {
focused = focused,
pressed = pressed,
hovered = hovered,
- active = active
+ active = active,
)
override fun toString() =
@@ -232,7 +232,7 @@ value class TabStripState(val state: ULong) : FocusableComponentState {
(if (pressed) CommonStateBitMask.Pressed else 0UL) or
(if (warning) CommonStateBitMask.Warning else 0UL) or
(if (error) CommonStateBitMask.Error else 0UL) or
- (if (active) CommonStateBitMask.Active else 0UL)
+ (if (active) CommonStateBitMask.Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Tabs.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Tabs.kt
index fcbddd007a4b..8ca509586733 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Tabs.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Tabs.kt
@@ -78,7 +78,7 @@ internal fun TabImpl(
CompositionLocalProvider(
LocalIndication provides NoIndication,
- LocalContentColor provides tabStyle.colors.contentFor(tabState).value
+ LocalContentColor provides tabStyle.colors.contentFor(tabState).value,
) {
val labelAlpha by tabStyle.contentAlpha.labelFor(tabState)
val iconAlpha by tabStyle.contentAlpha.iconFor(tabState)
@@ -92,7 +92,7 @@ internal fun TabImpl(
selected = tabData.selected,
interactionSource = interactionSource,
indication = NoIndication,
- role = Role.Tab
+ role = Role.Tab,
)
.drawBehind {
val strokeThickness = lineThickness.toPx()
@@ -105,12 +105,12 @@ internal fun TabImpl(
start = Offset(0 + capDxFix, startY),
end = Offset(endX - capDxFix, startY),
strokeWidth = strokeThickness,
- cap = StrokeCap.Round
+ cap = StrokeCap.Round,
)
}
.padding(tabStyle.metrics.tabPadding),
horizontalArrangement = Arrangement.spacedBy(tabStyle.metrics.closeContentGap),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
tabData.tabIconResource?.let { icon ->
val iconPainter = painterResource(icon, LocalResourceLoader.current)
@@ -120,7 +120,7 @@ internal fun TabImpl(
Text(
modifier = Modifier.alpha(labelAlpha),
text = tabData.label,
- color = tabStyle.colors.contentFor(tabState).value
+ color = tabStyle.colors.contentFor(tabState).value,
)
val showCloseIcon = when (tabData) {
is TabData.Default -> tabData.closable
@@ -147,10 +147,10 @@ internal fun TabImpl(
interactionSource = closeActionInteractionSource,
indication = null,
onClick = tabData.onClose,
- role = Role.Button
+ role = Role.Button,
).size(16.dp),
painter = closePainter,
- contentDescription = "Close tab ${tabData.label}"
+ contentDescription = "Close tab ${tabData.label}",
)
} else if (tabData.closable) {
Spacer(Modifier.size(16.dp))
@@ -215,7 +215,7 @@ value class TabState(val state: ULong) : SelectableComponentState {
focused = focused,
pressed = pressed,
hovered = hovered,
- active = active
+ active = active,
)
override fun toString() =
@@ -237,7 +237,7 @@ value class TabState(val state: ULong) : SelectableComponentState {
(if (focused) Focused else 0UL) or
(if (pressed) Pressed else 0UL) or
(if (hovered) Hovered else 0UL) or
- (if (active) Active else 0UL)
+ (if (active) Active else 0UL),
)
}
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Text.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Text.kt
index c1b676f15a1e..255b87a6f380 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Text.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/Text.kt
@@ -3,7 +3,6 @@ package org.jetbrains.jewel
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -36,7 +35,7 @@ fun Text(
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
onTextLayout: (TextLayoutResult) -> Unit = {},
- style: TextStyle = LocalTextStyle.current,
+ style: TextStyle = IntelliJTheme.defaultTextStyle,
) {
Text(
AnnotatedString(text),
@@ -55,7 +54,7 @@ fun Text(
maxLines,
emptyMap(),
onTextLayout,
- style
+ style,
)
}
@@ -77,7 +76,7 @@ fun Text(
maxLines: Int = Int.MAX_VALUE,
inlineContent: Map = emptyMap(),
onTextLayout: (TextLayoutResult) -> Unit = {},
- style: TextStyle = LocalTextStyle.current,
+ style: TextStyle = IntelliJTheme.defaultTextStyle,
) {
val textColor = color.takeOrElse {
style.color.takeOrElse {
@@ -97,8 +96,8 @@ fun Text(
fontFamily = fontFamily,
textDecoration = textDecoration,
fontStyle = fontStyle,
- letterSpacing = letterSpacing
- )
+ letterSpacing = letterSpacing,
+ ),
)
BasicText(text, modifier, mergedStyle, onTextLayout, overflow, softWrap, maxLines, minLines = 1, inlineContent)
}
@@ -110,9 +109,3 @@ val LocalTextStyle = staticCompositionLocalOf {
val LocalContentColor = staticCompositionLocalOf {
error("No ContentColor provided")
}
-
-@Composable
-fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit) {
- val mergedStyle = LocalTextStyle.current.merge(value)
- CompositionLocalProvider(LocalTextStyle provides mergedStyle, content = content)
-}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextArea.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextArea.kt
index 2abd67672394..01d5934f27cc 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextArea.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextArea.kt
@@ -4,7 +4,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.defaultMinSize
-import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Composable
@@ -24,12 +23,13 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.offset
import org.jetbrains.jewel.styling.TextAreaStyle
-import kotlin.math.max
+/**
+ * @param placeholder the optional placeholder to be displayed over the
+ * component when the [value] is empty.
+ */
@Composable
fun TextArea(
value: String,
@@ -37,9 +37,8 @@ fun TextArea(
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
- isError: Boolean = false,
+ outline: Outline = Outline.None,
placeholder: @Composable (() -> Unit)? = null,
- hint: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
@@ -69,9 +68,8 @@ fun TextArea(
modifier = modifier,
enabled = enabled,
readOnly = readOnly,
- isError = isError,
+ outline = outline,
placeholder = placeholder,
- hint = hint,
undecorated = undecorated,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
@@ -80,10 +78,14 @@ fun TextArea(
onTextLayout = onTextLayout,
style = style,
textStyle = textStyle,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
)
}
+/**
+ * @param placeholder the optional placeholder to be displayed over the
+ * component when the [value] is empty.
+ */
@Composable
fun TextArea(
value: TextFieldValue,
@@ -92,9 +94,8 @@ fun TextArea(
enabled: Boolean = true,
readOnly: Boolean = false,
placeholder: @Composable (() -> Unit)? = null,
- hint: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
- isError: Boolean = false,
+ outline: Outline = Outline.None,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions(),
@@ -104,13 +105,15 @@ fun TextArea(
textStyle: TextStyle = IntelliJTheme.defaultTextStyle,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
+ val minSize = style.metrics.minSize
InputField(
value = value,
onValueChange = onValueChange,
- modifier = modifier,
+ modifier = modifier
+ .defaultMinSize(minWidth = minSize.width, minHeight = minSize.height),
enabled = enabled,
readOnly = readOnly,
- isError = isError,
+ outline = outline,
undecorated = undecorated,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
@@ -120,108 +123,89 @@ fun TextArea(
onTextLayout = onTextLayout,
style = style,
textStyle = textStyle,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
) { innerTextField, state ->
- val minSize = style.metrics.minSize
-
TextAreaDecorationBox(
- modifier = Modifier
- .defaultMinSize(minWidth = minSize.width, minHeight = minSize.height),
innerTextField = innerTextField,
contentPadding = style.metrics.contentPadding,
placeholderTextColor = style.colors.placeholder,
placeholder = if (value.text.isEmpty()) placeholder else null,
- hintTextStyle = style.hintTextStyle,
- hintTextColor = style.colors.hintContentFor(state).value,
- hint = hint
+ textStyle = textStyle,
)
}
}
@Composable
private fun TextAreaDecorationBox(
- modifier: Modifier = Modifier,
innerTextField: @Composable () -> Unit,
contentPadding: PaddingValues,
+ textStyle: TextStyle,
placeholderTextColor: Color,
placeholder: @Composable (() -> Unit)?,
- hintTextStyle: TextStyle,
- hintTextColor: Color,
- hint: @Composable (() -> Unit)?,
) {
Layout(
- modifier = modifier,
content = {
if (placeholder != null) {
- Box(modifier = Modifier.layoutId(PLACEHOLDER_ID), contentAlignment = Alignment.Center) {
+ Box(
+ modifier = Modifier.layoutId(PLACEHOLDER_ID),
+ contentAlignment = Alignment.CenterStart,
+ ) {
CompositionLocalProvider(
+ LocalTextStyle provides textStyle.copy(color = placeholderTextColor),
LocalContentColor provides placeholderTextColor,
- content = placeholder
+ content = placeholder,
)
}
}
- Box(modifier = Modifier.layoutId(TEXT_FIELD_ID), propagateMinConstraints = true) {
+ Box(
+ modifier = Modifier.layoutId(TEXT_AREA_ID),
+ contentAlignment = Alignment.CenterStart,
+ propagateMinConstraints = true,
+ ) {
innerTextField()
}
-
- if (hint != null) {
- Box(Modifier.layoutId(HINT_ID).fillMaxWidth()) {
- CompositionLocalProvider(
- LocalTextStyle provides hintTextStyle,
- LocalContentColor provides hintTextColor,
- content = hint
- )
- }
- }
- }
+ },
) { measurables, incomingConstraints ->
val horizontalPadding =
- (contentPadding.calculateLeftPadding(layoutDirection) + contentPadding.calculateRightPadding(layoutDirection)).roundToPx()
+ (
+ contentPadding.calculateLeftPadding(layoutDirection) +
+ contentPadding.calculateRightPadding(layoutDirection)
+ ).roundToPx()
val verticalPadding =
- (contentPadding.calculateTopPadding() + contentPadding.calculateBottomPadding()).roundToPx()
+ (
+ contentPadding.calculateTopPadding() +
+ contentPadding.calculateBottomPadding()
+ ).roundToPx()
- // measure hint
- val hintConstraints = incomingConstraints.copy(minHeight = 0)
- val hintPlaceable = measurables.find { it.layoutId == HINT_ID }?.measure(hintConstraints)
- val occupiedSpaceVertically = hintPlaceable?.height ?: 0
+ val textAreaConstraints = incomingConstraints.offset(
+ horizontal = -horizontalPadding,
+ vertical = -verticalPadding,
+ ).copy(minHeight = 0)
- val constraintsWithoutPadding = incomingConstraints.offset(
- -horizontalPadding,
- -verticalPadding - occupiedSpaceVertically
- )
+ val textAreaPlaceable = measurables.first { it.layoutId == TEXT_AREA_ID }.measure(textAreaConstraints)
- val textConstraints = constraintsWithoutPadding
- val textFieldPlaceable = measurables.first { it.layoutId == TEXT_FIELD_ID }.measure(textConstraints)
-
- // measure placeholder
- val placeholderConstraints = textConstraints.copy(minWidth = 0, minHeight = 0)
+ // Measure placeholder
+ val placeholderConstraints = textAreaConstraints.copy(minWidth = 0, minHeight = 0)
val placeholderPlaceable = measurables.find { it.layoutId == PLACEHOLDER_ID }?.measure(placeholderConstraints)
val width = calculateWidth(
- textFieldPlaceable,
+ textAreaPlaceable,
placeholderPlaceable,
- horizontalPadding,
- hintPlaceable,
- constraintsWithoutPadding
+ textAreaConstraints,
)
val height = calculateHeight(
- textFieldPlaceable,
+ textAreaPlaceable,
placeholderPlaceable,
verticalPadding,
- hintPlaceable,
- constraintsWithoutPadding
+ textAreaConstraints,
)
layout(width, height) {
place(
height,
- contentPadding,
- hintPlaceable,
- textFieldPlaceable,
+ textAreaPlaceable,
placeholderPlaceable,
- layoutDirection,
- this@Layout
)
}
}
@@ -230,55 +214,44 @@ private fun TextAreaDecorationBox(
private fun calculateWidth(
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
- horizontalPadding: Int,
- hintPlaceable: Placeable?,
constraints: Constraints,
-): Int {
- return maxOf(
- textFieldPlaceable.width + horizontalPadding,
- (placeholderPlaceable?.width ?: 0) + horizontalPadding,
- hintPlaceable?.width ?: 0,
- constraints.minWidth
+): Int =
+ maxOf(
+ textFieldPlaceable.width,
+ placeholderPlaceable?.width ?: 0,
)
-}
+ .coerceAtLeast(constraints.minWidth)
private fun calculateHeight(
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
verticalPadding: Int,
- hintPlaceable: Placeable?,
constraints: Constraints,
): Int {
- val middleSection = maxOf(
+ val textAreaHeight = maxOf(
textFieldPlaceable.height,
- placeholderPlaceable?.height ?: 0
- ) + verticalPadding
- val wrappedHeight = (hintPlaceable?.height ?: 0) + middleSection
- return max(wrappedHeight, constraints.minHeight)
+ placeholderPlaceable?.height ?: 0,
+ )
+ return (textAreaHeight + verticalPadding).coerceAtLeast(constraints.minHeight)
}
private fun Placeable.PlacementScope.place(
height: Int,
- contentPadding: PaddingValues,
- hintPlaceable: Placeable?,
- textFieldPlaceable: Placeable,
+ textAreaPlaceable: Placeable,
placeholderPlaceable: Placeable?,
- layoutDirection: LayoutDirection,
- density: Density,
-) = with(density) {
- hintPlaceable?.placeRelative(
+) {
+ // placed center vertically
+ textAreaPlaceable.placeRelative(
0,
- height - hintPlaceable.height
+ Alignment.CenterVertically.align(textAreaPlaceable.height, height),
)
- val y = contentPadding.calculateTopPadding().roundToPx()
- val x = contentPadding.calculateLeftPadding(layoutDirection).roundToPx()
-
- textFieldPlaceable.placeRelative(x, y)
-
- placeholderPlaceable?.placeRelative(x, y)
+ // placed similar to the input text above
+ placeholderPlaceable?.placeRelative(
+ 0,
+ Alignment.CenterVertically.align(placeholderPlaceable.height, height),
+ )
}
private const val PLACEHOLDER_ID = "Placeholder"
-private const val TEXT_FIELD_ID = "TextField"
-private const val HINT_ID = "Hint"
+private const val TEXT_AREA_ID = "TextField"
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextField.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextField.kt
index 0fb482646cec..f499a8f0e135 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextField.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/TextField.kt
@@ -23,11 +23,14 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.offset
import org.jetbrains.jewel.styling.TextFieldStyle
import kotlin.math.max
+/**
+ * @param placeholder the optional placeholder to be displayed over the
+ * component when the [value] is empty.
+ */
@Composable
fun TextField(
value: String,
@@ -35,7 +38,7 @@ fun TextField(
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
- isError: Boolean = false,
+ outline: Outline = Outline.None,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
@@ -65,7 +68,7 @@ fun TextField(
modifier = modifier,
enabled = enabled,
readOnly = readOnly,
- isError = isError,
+ outline = outline,
placeholder = placeholder,
trailingIcon = trailingIcon,
undecorated = undecorated,
@@ -74,10 +77,14 @@ fun TextField(
keyboardActions = keyboardActions,
onTextLayout = onTextLayout,
style = style,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
)
}
+/**
+ * @param placeholder the optional placeholder to be displayed over the
+ * component when the [value] is empty.
+ */
@Composable
fun TextField(
value: TextFieldValue,
@@ -85,7 +92,7 @@ fun TextField(
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
- isError: Boolean = false,
+ outline: Outline = Outline.None,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
undecorated: Boolean = false,
@@ -103,7 +110,7 @@ fun TextField(
modifier = modifier,
enabled = enabled,
readOnly = readOnly,
- isError = isError,
+ outline = outline,
undecorated = undecorated,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
@@ -113,17 +120,18 @@ fun TextField(
onTextLayout = onTextLayout,
style = style,
textStyle = textStyle,
- interactionSource = interactionSource
+ interactionSource = interactionSource,
) { innerTextField, _ ->
val minSize = style.metrics.minSize
TextFieldDecorationBox(
- modifier = Modifier.defaultMinSize(minHeight = minSize.width, minWidth = minSize.height)
+ modifier = Modifier.defaultMinSize(minWidth = minSize.width, minHeight = minSize.height)
.padding(style.metrics.contentPadding),
innerTextField = innerTextField,
+ textStyle = textStyle,
placeholderTextColor = style.colors.placeholder,
placeholder = if (value.text.isEmpty()) placeholder else null,
- trailingIcon = trailingIcon
+ trailingIcon = trailingIcon,
)
}
}
@@ -132,6 +140,7 @@ fun TextField(
private fun TextFieldDecorationBox(
modifier: Modifier = Modifier,
innerTextField: @Composable () -> Unit,
+ textStyle: TextStyle,
placeholderTextColor: Color,
placeholder: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
@@ -147,8 +156,9 @@ private fun TextFieldDecorationBox(
if (placeholder != null) {
Box(modifier = Modifier.layoutId(PLACEHOLDER_ID), contentAlignment = Alignment.Center) {
CompositionLocalProvider(
+ LocalTextStyle provides textStyle.copy(color = placeholderTextColor),
LocalContentColor provides placeholderTextColor,
- content = placeholder
+ content = placeholder,
)
}
}
@@ -156,40 +166,37 @@ private fun TextFieldDecorationBox(
Box(modifier = Modifier.layoutId(TEXT_FIELD_ID), propagateMinConstraints = true) {
innerTextField()
}
- }
+ },
) { measurables, incomingConstraints ->
// used to calculate the constraints for measuring elements that will be placed in a row
var occupiedSpaceHorizontally = 0
-
- val constraintsWithoutPadding = incomingConstraints
-
- val iconsConstraints = constraintsWithoutPadding.copy(minWidth = 0, minHeight = 0)
+ val iconConstraints = incomingConstraints.copy(minWidth = 0, minHeight = 0)
// measure trailing icon
val trailingPlaceable = measurables.find { it.layoutId == TRAILING_ID }
- ?.measure(iconsConstraints)
+ ?.measure(iconConstraints)
occupiedSpaceHorizontally += trailingPlaceable?.width ?: 0
- val textConstraints = constraintsWithoutPadding.offset(
- horizontal = -occupiedSpaceHorizontally
+ val textFieldConstraints = incomingConstraints.offset(
+ horizontal = -occupiedSpaceHorizontally,
).copy(minHeight = 0)
- val textFieldPlaceable = measurables.first { it.layoutId == TEXT_FIELD_ID }.measure(textConstraints)
+ val textFieldPlaceable = measurables.first { it.layoutId == TEXT_FIELD_ID }.measure(textFieldConstraints)
// measure placeholder
- val placeholderConstraints = textConstraints.copy(minWidth = 0)
+ val placeholderConstraints = textFieldConstraints.copy(minWidth = 0)
val placeholderPlaceable = measurables.find { it.layoutId == PLACEHOLDER_ID }?.measure(placeholderConstraints)
val width = calculateWidth(
trailingPlaceable,
textFieldPlaceable,
placeholderPlaceable,
- incomingConstraints
+ incomingConstraints,
)
val height = calculateHeight(
trailingPlaceable,
textFieldPlaceable,
placeholderPlaceable,
- incomingConstraints
+ incomingConstraints,
)
layout(width, height) {
@@ -199,7 +206,6 @@ private fun TextFieldDecorationBox(
trailingPlaceable,
textFieldPlaceable,
placeholderPlaceable,
- this@Layout
)
}
}
@@ -213,7 +219,7 @@ private fun calculateWidth(
): Int {
val middleSection = maxOf(
textFieldPlaceable.width,
- placeholderPlaceable?.width ?: 0
+ placeholderPlaceable?.width ?: 0,
)
val wrappedWidth = middleSection + (trailingPlaceable?.width ?: 0)
return max(wrappedWidth, constraints.minWidth)
@@ -224,14 +230,12 @@ private fun calculateHeight(
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
constraints: Constraints,
-): Int {
- return maxOf(
- textFieldPlaceable.height,
- placeholderPlaceable?.height ?: 0,
- trailingPlaceable?.height ?: 0,
- constraints.minHeight
- )
-}
+): Int = maxOf(
+ textFieldPlaceable.height,
+ placeholderPlaceable?.height ?: 0,
+ trailingPlaceable?.height ?: 0,
+ constraints.minHeight,
+)
private fun Placeable.PlacementScope.place(
height: Int,
@@ -239,28 +243,24 @@ private fun Placeable.PlacementScope.place(
trailingPlaceable: Placeable?,
textFieldPlaceable: Placeable,
placeholderPlaceable: Placeable?,
- density: Density,
-) = with(density) {
+) {
// placed center vertically and to the end edge horizontally
trailingPlaceable?.placeRelative(
width - trailingPlaceable.width,
- Alignment.CenterVertically.align(trailingPlaceable.height, height)
+ Alignment.CenterVertically.align(trailingPlaceable.height, height),
)
- // placed center vertically and after the leading icon horizontally if single line text field
- // placed to the top with padding for multi line text field
+ // placed center vertically
textFieldPlaceable.placeRelative(
0,
- Alignment.CenterVertically.align(textFieldPlaceable.height, height)
+ Alignment.CenterVertically.align(textFieldPlaceable.height, height),
)
// placed similar to the input text above
- placeholderPlaceable?.let {
- it.placeRelative(
- 0,
- Alignment.CenterVertically.align(it.height, height)
- )
- }
+ placeholderPlaceable?.placeRelative(
+ 0,
+ Alignment.CenterVertically.align(placeholderPlaceable.height, height),
+ )
}
private const val PLACEHOLDER_ID = "Placeholder"
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/Border.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/Border.kt
similarity index 80%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/Border.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/Border.kt
index 2385da4e1cf7..b8d905abb509 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/Border.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/Border.kt
@@ -32,6 +32,7 @@ import androidx.compose.ui.node.Ref
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.isUnspecified
import androidx.compose.ui.unit.takeOrElse
import androidx.compose.ui.unit.toSize
@@ -49,14 +50,26 @@ fun Modifier.border(stroke: Stroke, shape: Shape): Modifier = when (stroke) {
width = stroke.width,
brush = stroke.brush,
shape = shape,
- expand = stroke.expand
+ expand = stroke.expand,
)
}
-fun Modifier.border(alignment: Stroke.Alignment, width: Dp, color: Color, shape: Shape = RectangleShape, expand: Dp = Dp.Unspecified) =
+fun Modifier.border(
+ alignment: Stroke.Alignment,
+ width: Dp,
+ color: Color,
+ shape: Shape = RectangleShape,
+ expand: Dp = Dp.Unspecified,
+) =
border(alignment, width, SolidColor(color), shape, expand)
-fun Modifier.border(alignment: Stroke.Alignment, width: Dp, brush: Brush, shape: Shape = RectangleShape, expand: Dp = Dp.Unspecified): Modifier =
+fun Modifier.border(
+ alignment: Stroke.Alignment,
+ width: Dp,
+ brush: Brush,
+ shape: Shape = RectangleShape,
+ expand: Dp = Dp.Unspecified,
+): Modifier =
if (alignment == Stroke.Alignment.Inside && expand.isUnspecified) {
// The compose native border modifier(androidx.compose.foundation.border) draws the border inside the shape,
// so we can just use that for getting a more native experience when drawing inside borders
@@ -81,11 +94,13 @@ private fun Modifier.drawBorderWithAlignment(
val strokeWidthPx = max(
min(
if (width == Dp.Hairline) 1f else ceil(width.toPx()),
- ceil(size.minDimension / 2)
+ ceil(size.minDimension / 2),
),
- 1f
+ 1f,
)
- val expandWidthPx = expand.takeOrElse { Dp.Hairline }.toPx()
+
+ val expandWidthPx = expand.takeOrElse { 0.dp }.toPx()
+
when (val outline = shape.createOutline(size, layoutDirection, this)) {
is Outline.Rectangle -> {
when (shape) {
@@ -95,19 +110,40 @@ private fun Modifier.drawBorderWithAlignment(
Outline.Rounded(RoundRect(outline.rect)),
brush,
strokeWidthPx,
- expandWidthPx
+ expandWidthPx,
)
- else -> drawRectBorder(borderCacheRef, alignment, outline, brush, strokeWidthPx, expandWidthPx)
+ else -> drawRectBorder(
+ borderCacheRef,
+ alignment,
+ outline,
+ brush,
+ strokeWidthPx,
+ expandWidthPx,
+ )
}
}
- is Outline.Rounded -> drawRoundedBorder(borderCacheRef, alignment, outline, brush, strokeWidthPx, expandWidthPx)
+ is Outline.Rounded -> drawRoundedBorder(
+ borderCacheRef,
+ alignment,
+ outline,
+ brush,
+ strokeWidthPx,
+ expandWidthPx,
+ )
- is Outline.Generic -> drawGenericBorder(borderCacheRef, alignment, outline, brush, strokeWidthPx, expandWidthPx)
+ is Outline.Generic -> drawGenericBorder(
+ borderCacheRef,
+ alignment,
+ outline,
+ brush,
+ strokeWidthPx,
+ expandWidthPx,
+ )
}
}
- }
+ },
)
},
inspectorInfo = debugInspectorInfo {
@@ -122,7 +158,7 @@ private fun Modifier.drawBorderWithAlignment(
}
properties["shape"] = shape
properties["expand"] = expand
- }
+ },
)
private class BorderCache(
@@ -151,7 +187,7 @@ private class BorderCache(
targetImageBitmap = ImageBitmap(
borderSize.width,
borderSize.height,
- config = config
+ config = config,
).also {
imageBitmap = it
}
@@ -166,12 +202,12 @@ private class BorderCache(
this,
layoutDirection,
targetCanvas,
- drawSize
+ drawSize,
) {
drawRect(
color = Color.Black,
size = drawSize,
- blendMode = BlendMode.Clear
+ blendMode = BlendMode.Clear,
)
block()
}
@@ -219,26 +255,27 @@ private fun ContentDrawScope.drawRoundedBorder(
strokeWidthPx: Float,
expandWidthPx: Float,
) {
- val rrect = when (alignment) {
+ val roundRect = when (alignment) {
Stroke.Alignment.Inside -> outline.roundRect.inflate(expandWidthPx - strokeWidthPx / 2f)
Stroke.Alignment.Center -> outline.roundRect.inflate(expandWidthPx)
Stroke.Alignment.Outside -> outline.roundRect.inflate(expandWidthPx + strokeWidthPx / 2f)
}
- if (rrect.hasRightAngle()) {
+ if (roundRect.hasAtLeastOneNonRoundedCorner()) {
+ // Note: why do we need this? The Outline API can handle it just fine
val cache = borderCacheRef.obtain()
val borderPath = cache.obtainPath().apply {
reset()
fillType = PathFillType.EvenOdd
- addRoundRect(rrect.deflate(strokeWidthPx / 2f))
- addRoundRect(rrect.inflate(strokeWidthPx / 2f))
+ addRoundRect(roundRect.deflate(strokeWidthPx / 2f))
+ addRoundRect(roundRect.inflate(strokeWidthPx / 2f))
}
drawPath(borderPath, brush)
} else {
drawOutline(
- outline = Outline.Rounded(rrect),
+ outline = Outline.Rounded(roundRect),
brush = brush,
- style = DrawScopeStroke(strokeWidthPx)
+ style = DrawScopeStroke(strokeWidthPx),
)
}
}
@@ -276,10 +313,12 @@ private fun CacheDrawScope.drawGenericBorder(
inner -> {
return@onDrawWithContent
}
+
-inner -> {
// Samply draw the outline when abs(outer) and abs(inner) are the same
drawOutline(outline, brush, style = DrawScopeStroke(outer * 2f))
}
+
else -> {
val config: ImageBitmapConfig
val colorFilter: ColorFilter?
@@ -300,13 +339,13 @@ private fun CacheDrawScope.drawGenericBorder(
val cacheImageBitmap: ImageBitmap
val pathBoundsSize = IntSize(
ceil(pathBounds.width).toInt(),
- ceil(pathBounds.height).toInt()
+ ceil(pathBounds.height).toInt(),
)
with(borderCache) {
cacheImageBitmap = drawBorderCache(
pathBoundsSize,
- config
+ config,
) {
translate(-pathBounds.left, -pathBounds.top) {
if (inner < 0f && outer > 0f) {
@@ -317,7 +356,12 @@ private fun CacheDrawScope.drawGenericBorder(
drawPath(path = outline.path, brush = brush, style = DrawScopeStroke(outer * 2f))
if (inner > 0f) {
- drawPath(path = outline.path, brush = brush, blendMode = BlendMode.Clear, style = DrawScopeStroke(inner * 2f))
+ drawPath(
+ path = outline.path,
+ brush = brush,
+ blendMode = BlendMode.Clear,
+ style = DrawScopeStroke(inner * 2f),
+ )
}
drawPath(path = outline.path, brush = brush, blendMode = BlendMode.Clear)
@@ -327,7 +371,12 @@ private fun CacheDrawScope.drawGenericBorder(
drawPath(path = outline.path, brush = brush, style = DrawScopeStroke(-inner * 2f))
if (outer < 0f) {
- drawPath(path = outline.path, brush = brush, blendMode = BlendMode.Clear, style = DrawScopeStroke(-outer * 2f))
+ drawPath(
+ path = outline.path,
+ brush = brush,
+ blendMode = BlendMode.Clear,
+ style = DrawScopeStroke(-outer * 2f),
+ )
}
drawPath(path = outerMaskPath, brush = brush, blendMode = BlendMode.Clear)
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/PointerInput.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/PointerInput.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/PointerInput.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/PointerInput.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/RoundRect.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/RoundRect.kt
similarity index 90%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/RoundRect.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/RoundRect.kt
index 6b1f9b763628..bb508a2fc5ac 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/RoundRect.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/RoundRect.kt
@@ -11,7 +11,7 @@ internal fun RoundRect.inflate(delta: Float) = RoundRect(
topLeftCornerRadius = CornerRadius(topLeftCornerRadius.x + delta, topLeftCornerRadius.y + delta),
topRightCornerRadius = CornerRadius(topRightCornerRadius.x + delta, topRightCornerRadius.y + delta),
bottomLeftCornerRadius = CornerRadius(bottomLeftCornerRadius.x + delta, bottomLeftCornerRadius.y + delta),
- bottomRightCornerRadius = CornerRadius(bottomRightCornerRadius.x + delta, bottomRightCornerRadius.y + delta)
+ bottomRightCornerRadius = CornerRadius(bottomRightCornerRadius.x + delta, bottomRightCornerRadius.y + delta),
)
internal fun RoundRect.deflate(delta: Float) = RoundRect(
@@ -22,10 +22,10 @@ internal fun RoundRect.deflate(delta: Float) = RoundRect(
topLeftCornerRadius = CornerRadius(topLeftCornerRadius.x - delta, topLeftCornerRadius.y - delta),
topRightCornerRadius = CornerRadius(topRightCornerRadius.x - delta, topRightCornerRadius.y - delta),
bottomLeftCornerRadius = CornerRadius(bottomLeftCornerRadius.x - delta, bottomLeftCornerRadius.y - delta),
- bottomRightCornerRadius = CornerRadius(bottomRightCornerRadius.x - delta, bottomRightCornerRadius.y - delta)
+ bottomRightCornerRadius = CornerRadius(bottomRightCornerRadius.x - delta, bottomRightCornerRadius.y - delta),
)
-internal fun RoundRect.hasRightAngle() =
+internal fun RoundRect.hasAtLeastOneNonRoundedCorner() =
topLeftCornerRadius.x == 0f && topLeftCornerRadius.y == 0f ||
topRightCornerRadius.x == 0f && topRightCornerRadius.y == 0f ||
bottomLeftCornerRadius.x == 0f && bottomLeftCornerRadius.y == 0f ||
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/Stroke.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/Stroke.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/Stroke.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/Stroke.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/Keybindings.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/Keybindings.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/Keybindings.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/Keybindings.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt
similarity index 98%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt
index 6197624bb43b..e748ac3a0aa0 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableColumnOnKeyEvent.kt
@@ -141,8 +141,8 @@ open class DefaultSelectableOnKeyEvent(
selectableState.addElementsToSelection(
listOf(
currentIndex,
- prevIndex
- )
+ prevIndex,
+ ),
)
selectableState.lastKeyEventUsedMouse = true
}
@@ -170,8 +170,8 @@ open class DefaultSelectableOnKeyEvent(
selectableState.addElementsToSelection(
listOf(
currentIndex,
- nextSelectableIndex
- )
+ nextSelectableIndex,
+ ),
)
selectableState.lastKeyEventUsedMouse = true
}
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyColumn.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyColumn.kt
similarity index 98%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyColumn.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyColumn.kt
index bb84925cbbbb..fa926ca6eaac 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyColumn.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyColumn.kt
@@ -68,7 +68,7 @@ fun SelectableLazyColumn(
interactionSource = interactionSource,
keyActions = keyActions.handleOnKeyEvent(rememberCoroutineScope()),
pointerHandlingScopedActions = pointerHandlingScopedActions,
- content = content
+ content = content,
)
}
@@ -97,7 +97,7 @@ internal fun BaseSelectableLazyColumn(
reverseLayout = reverseLayout,
verticalArrangement = verticalArrangement,
horizontalAlignment = horizontalAlignment,
- flingBehavior = flingBehavior
+ flingBehavior = flingBehavior,
) {
state.clearKeys()
SelectableLazyListScopeContainer(state, pointerHandlingScopedActions).apply(content)
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListScope.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListScope.kt
similarity index 98%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListScope.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListScope.kt
index f12749f19f5c..6477617b1001 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListScope.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListScope.kt
@@ -149,7 +149,7 @@ internal class SelectableLazyListScopeContainer(
Box(
Modifier
.then(if (selectable) Modifier.selectable(selectableKey, scope) else Modifier)
- .then(if (focusable) Modifier.focusable(selectableKey as SelectableKey.Focusable, isFocused) else Modifier)
+ .then(if (focusable) Modifier.focusable(selectableKey as SelectableKey.Focusable, isFocused) else Modifier),
) {
content(SelectableLazyItemScope(isSelected, isFocused))
}
@@ -170,7 +170,7 @@ internal class SelectableLazyListScopeContainer(
} else {
SelectableKey.NotFocusable(
key(it),
- selectable(it)
+ selectable(it),
)
}
}
@@ -187,11 +187,11 @@ internal class SelectableLazyListScopeContainer(
Box(
Modifier
.then(if (selectable(index)) Modifier.selectable(selectableKeys[index]) else Modifier)
- .then(if (focusable(index)) Modifier.focusable(selectableKeys[index] as SelectableKey.Focusable, isFocused) else Modifier)
+ .then(if (focusable(index)) Modifier.focusable(selectableKeys[index] as SelectableKey.Focusable, isFocused) else Modifier),
) {
itemContent(SelectableLazyItemScope(isFocused, isSelected), index)
}
- }
+ },
)
}
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/lazy/SelectableLazyListState.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BasicLazyTree.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BasicLazyTree.kt
similarity index 78%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BasicLazyTree.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BasicLazyTree.kt
index b21982a4460a..31feeffacd4a 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BasicLazyTree.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BasicLazyTree.kt
@@ -29,6 +29,15 @@ import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import org.jetbrains.jewel.CommonStateBitMask
+import org.jetbrains.jewel.CommonStateBitMask.Active
+import org.jetbrains.jewel.CommonStateBitMask.Enabled
+import org.jetbrains.jewel.CommonStateBitMask.Focused
+import org.jetbrains.jewel.CommonStateBitMask.Hovered
+import org.jetbrains.jewel.CommonStateBitMask.Pressed
+import org.jetbrains.jewel.CommonStateBitMask.Selected
+import org.jetbrains.jewel.InteractiveComponentState
+import org.jetbrains.jewel.SelectableComponentState
import org.jetbrains.jewel.foundation.lazy.SelectableLazyColumn
import org.jetbrains.jewel.foundation.lazy.SelectableLazyItemScope
import org.jetbrains.jewel.foundation.utils.Log
@@ -99,7 +108,7 @@ fun BasicLazyTree(
state = treeState.delegate,
keyActions = keyActions,
interactionSource = interactionSource,
- pointerHandlingScopedActions = pointerEventScopedActions
+ pointerHandlingScopedActions = pointerEventScopedActions,
) {
items(
count = flattenedTree.size,
@@ -107,13 +116,13 @@ fun BasicLazyTree(
val idPath = flattenedTree[it].idPath()
idPath
},
- contentType = { flattenedTree[it].data }
+ contentType = { flattenedTree[it].data },
) { itemIndex ->
val element = flattenedTree[itemIndex]
val elementState = TreeElementState.of(
focused = isFocused,
selected = isSelected,
- expanded = (element as? Tree.Element.Node)?.let { it.idPath() in treeState.openNodes } ?: false
+ expanded = (element as? Tree.Element.Node)?.let { it.idPath() in treeState.openNodes } ?: false,
)
val backgroundShape by remember { mutableStateOf(RoundedCornerShape(elementBackgroundCornerSize)) }
@@ -126,32 +135,32 @@ fun BasicLazyTree(
elementBackgroundSelectedFocused,
elementBackgroundFocused,
elementBackgroundSelected,
- backgroundShape
+ backgroundShape,
)
.padding(elementContentPadding)
.padding(start = (element.depth * indentSize.value).dp)
.clickable(
interactionSource = remember { MutableInteractionSource() },
- indication = null
+ indication = null,
) {
(pointerEventScopedActions as? DefaultTreeViewPointerEventAction)?.notifyItemClicked(
item = flattenedTree[itemIndex] as Tree.Element,
scope = scope,
doubleClickTimeDelayMillis = platformDoubleClickDelay.inWholeMilliseconds,
onElementClick = onElementClick,
- onElementDoubleClick = onElementDoubleClick
+ onElementDoubleClick = onElementDoubleClick,
)
- }
+ },
) {
if (element is Tree.Element.Node) {
Box(
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
- indication = null
+ indication = null,
) {
treeState.toggleNode(element.idPath())
onElementDoubleClick(element as Tree.Element)
- }
+ },
) {
chevronContent(elementState)
}
@@ -177,54 +186,90 @@ private fun Modifier.elementBackground(
state.isSelected && !state.isFocused -> selected
else -> Color.Unspecified
},
- shape = backgroundShape
+ shape = backgroundShape,
)
@Immutable
@JvmInline
-value class TreeElementState(val state: ULong) {
+value class TreeElementState(val state: ULong) : InteractiveComponentState, SelectableComponentState {
@Stable
- val isFocused: Boolean
+ override val isActive: Boolean
+ get() = state and Active != 0UL
+
+ @Stable
+ override val isEnabled: Boolean
+ get() = state and Enabled != 0UL
+
+ @Stable
+ override val isFocused: Boolean
get() = state and Focused != 0UL
@Stable
- val isSelected: Boolean
+ override val isPressed: Boolean
+ get() = state and Pressed != 0UL
+
+ @Stable
+ override val isHovered: Boolean
+ get() = state and Hovered != 0UL
+
+ @Stable
+ override val isSelected: Boolean
get() = state and Selected != 0UL
@Stable
val isExpanded: Boolean
get() = state and Expanded != 0UL
- fun copy(
- focused: Boolean = isFocused,
- selected: Boolean = isSelected,
- expanded: Boolean = isExpanded,
- ) = of(focused, selected, expanded)
+ override fun toString(): String =
+ "${javaClass.simpleName}(enabled=$isEnabled, focused=$isFocused, expanded=$isExpanded, " +
+ "pressed=$isPressed, hovered=$isHovered, active=$isActive, selected=$isSelected)"
- override fun toString() =
- "${javaClass.simpleName}(isFocused=$isFocused, isSelected=$isSelected, isExpanded=$isExpanded)"
+ fun copy(
+ enabled: Boolean = isEnabled,
+ focused: Boolean = isFocused,
+ expanded: Boolean = isExpanded,
+ pressed: Boolean = isPressed,
+ hovered: Boolean = isHovered,
+ active: Boolean = isActive,
+ selected: Boolean = isSelected,
+ ) = of(
+ enabled = enabled,
+ focused = focused,
+ expanded = expanded,
+ pressed = pressed,
+ hovered = hovered,
+ active = active,
+ selected = selected,
+ )
companion object {
- private val Focused = 1UL shl 0
- private val Hovered = 1UL shl 1
- private val Selected = 1UL shl 2
- private val Expanded = 1UL shl 3
+ private const val EXPANDED_BIT_OFFSET = CommonStateBitMask.FIRST_AVAILABLE_OFFSET
+
+ private val Expanded = 1UL shl EXPANDED_BIT_OFFSET
fun of(
- focused: Boolean,
- selected: Boolean,
- expanded: Boolean,
+ enabled: Boolean = true,
+ focused: Boolean = false,
+ expanded: Boolean = false,
+ hovered: Boolean = false,
+ pressed: Boolean = false,
+ active: Boolean = false,
+ selected: Boolean = false,
) = TreeElementState(
- (if (focused) Focused else 0UL) or
+ (if (expanded) Expanded else 0UL) or
+ (if (enabled) Enabled else 0UL) or
+ (if (focused) Focused else 0UL) or
+ (if (pressed) Pressed else 0UL) or
+ (if (hovered) Hovered else 0UL) or
(if (selected) Selected else 0UL) or
- (if (expanded) Expanded else 0UL)
+ (if (active) Active else 0UL),
)
}
}
-private suspend fun flattenTree(
+private fun flattenTree(
element: Tree.Element<*>,
openNodes: SnapshotStateList,
allNodes: SnapshotStateList,
@@ -241,7 +286,7 @@ private suspend fun flattenTree(
openNodes.removeAll(
buildList {
getAllSubNodes(element)
- }
+ },
)
}
}
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BuildTree.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BuildTree.kt
similarity index 97%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BuildTree.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BuildTree.kt
index deda0a079893..4b4c01921f69 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BuildTree.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/BuildTree.kt
@@ -49,7 +49,7 @@ class TreeBuilder : TreeGeneratorScope {
parent = null,
previous = previous,
next = null,
- id = elementBuilder.id
+ id = elementBuilder.id,
)
is Element.Node -> Tree.Element.Node(
@@ -60,7 +60,7 @@ class TreeBuilder : TreeGeneratorScope {
childrenGenerator = { parent -> generateElements(parent, elementBuilder) },
previous = previous,
next = null,
- id = elementBuilder.id
+ id = elementBuilder.id,
)
}
elements.add(current)
@@ -87,7 +87,7 @@ private fun generateElements(
parent = parent,
previous = previous,
next = null,
- id = elementBuilder.id
+ id = elementBuilder.id,
)
is TreeBuilder.Element.Node -> Tree.Element.Node(
@@ -98,7 +98,7 @@ private fun generateElements(
childrenGenerator = { generateElements(it, elementBuilder) },
previous = previous,
next = null,
- id = elementBuilder.id
+ id = elementBuilder.id,
)
}
previous.next = current
@@ -116,6 +116,7 @@ private fun evaluatePrevious(element: Tree.Element): Tree.Element = wh
}
interface TreeGeneratorScope {
+
fun addNode(
data: T,
id: Any = data.hashCode(),
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewKeybindings.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewKeybindings.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewKeybindings.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewKeybindings.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewOnKeyEvent.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewOnKeyEvent.kt
similarity index 97%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewOnKeyEvent.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewOnKeyEvent.kt
index db966c0aa2e0..d53666e7432b 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewOnKeyEvent.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/DefaultTreeViewOnKeyEvent.kt
@@ -56,9 +56,9 @@ open class DefaultTreeViewOnKeyEvent(
treeState.addElementsToSelection(
listOf(
currentIndex,
- prevIndex
+ prevIndex,
),
- null
+ null,
)
treeState.lastKeyEventUsedMouse = true
}
@@ -88,9 +88,9 @@ open class DefaultTreeViewOnKeyEvent(
treeState.addElementsToSelection(
listOf(
currentIndex,
- nextFlattenIndex
+ nextFlattenIndex,
),
- null
+ null,
)
treeState.lastKeyEventUsedMouse = true
}
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/KeyBindingScopedActions.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/KeyBindingScopedActions.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/KeyBindingScopedActions.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/KeyBindingScopedActions.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/Tree.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/Tree.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/Tree.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/Tree.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeState.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeState.kt
similarity index 98%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeState.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeState.kt
index 6a1563afc943..1dab02653541 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeState.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeState.kt
@@ -13,8 +13,8 @@ fun rememberTreeState(selectionMode: SelectionMode = SelectionMode.Single) = rem
TreeState(
SelectableLazyListState(
LazyListState(),
- selectionMode
- )
+ selectionMode,
+ ),
)
}
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeViewOnKeyEvent.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeViewOnKeyEvent.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeViewOnKeyEvent.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/tree/TreeViewOnKeyEvent.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/utils/Logger.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/utils/Logger.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/utils/Logger.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/utils/Logger.kt
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/utils/ModifierExtensions.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/utils/ModifierExtensions.kt
similarity index 100%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/utils/ModifierExtensions.kt
rename to platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/foundation/utils/ModifierExtensions.kt
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ButtonStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ButtonStyling.kt
index 9f28f3cad7c7..c1270ac3d0f2 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ButtonStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ButtonStyling.kt
@@ -37,8 +37,8 @@ interface ButtonColors {
focused = backgroundFocused,
pressed = backgroundPressed,
hovered = backgroundHovered,
- active = background
- )
+ active = background,
+ ),
)
val content: Color
@@ -55,15 +55,15 @@ interface ButtonColors {
focused = contentFocused,
pressed = contentPressed,
hovered = contentHovered,
- active = content
- )
+ active = content,
+ ),
)
- val border: Color
- val borderDisabled: Color
- val borderFocused: Color
- val borderPressed: Color
- val borderHovered: Color
+ val border: Brush
+ val borderDisabled: Brush
+ val borderFocused: Brush
+ val borderPressed: Brush
+ val borderHovered: Brush
@Composable
fun borderFor(state: ButtonState) = rememberUpdatedState(
@@ -73,8 +73,8 @@ interface ButtonColors {
focused = borderFocused,
pressed = borderPressed,
hovered = borderHovered,
- active = border
- )
+ active = border,
+ ),
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/CheckboxStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/CheckboxStyling.kt
index 0fac68f7a57f..31fd74301a6c 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/CheckboxStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/CheckboxStyling.kt
@@ -33,7 +33,7 @@ interface CheckboxColors {
!state.isEnabled -> checkboxBackgroundDisabled
state.toggleableState == ToggleableState.On -> checkboxBackgroundSelected
else -> checkboxBackground
- }
+ },
)
val content: Color
@@ -46,20 +46,7 @@ interface CheckboxColors {
!state.isEnabled -> contentDisabled
state.toggleableState == ToggleableState.On -> contentSelected
else -> content
- }
- )
-
- val checkboxBorder: Color
- val checkboxBorderDisabled: Color
- val checkboxBorderSelected: Color
-
- @Composable
- fun borderFor(state: CheckboxState) = rememberUpdatedState(
- when {
- !state.isEnabled -> checkboxBorderDisabled
- state.toggleableState == ToggleableState.On -> checkboxBorderSelected
- else -> checkboxBorder
- }
+ },
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ChipStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ChipStyling.kt
index d277d38c1a9b..7297998e2670 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ChipStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ChipStyling.kt
@@ -10,8 +10,8 @@ import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.DpSize
import org.jetbrains.jewel.ChipState
+import org.jetbrains.jewel.IntelliJTheme
@Stable
interface ChipStyle {
@@ -28,17 +28,31 @@ interface ChipColors {
val backgroundFocused: Brush
val backgroundPressed: Brush
val backgroundHovered: Brush
+ val backgroundSelected: Brush
+ val backgroundSelectedDisabled: Brush
+ val backgroundSelectedPressed: Brush
+ val backgroundSelectedFocused: Brush
+ val backgroundSelectedHovered: Brush
@Composable
fun backgroundFor(state: ChipState) = rememberUpdatedState(
- state.chooseValue(
- normal = background,
- disabled = backgroundDisabled,
- focused = backgroundFocused,
- pressed = backgroundPressed,
- hovered = backgroundHovered,
- active = background
- )
+ if (state.isSelected) {
+ when {
+ !state.isEnabled -> backgroundSelectedDisabled
+ state.isPressed -> backgroundSelectedPressed
+ state.isFocused -> backgroundSelectedFocused
+ state.isHovered -> backgroundSelectedHovered
+ else -> backgroundSelected
+ }
+ } else {
+ when {
+ !state.isEnabled -> backgroundDisabled
+ state.isPressed -> backgroundPressed
+ state.isFocused -> backgroundFocused
+ state.isHovered -> backgroundHovered
+ else -> background
+ }
+ },
)
val content: Color
@@ -46,17 +60,31 @@ interface ChipColors {
val contentFocused: Color
val contentPressed: Color
val contentHovered: Color
+ val contentSelected: Color
+ val contentSelectedDisabled: Color
+ val contentSelectedPressed: Color
+ val contentSelectedFocused: Color
+ val contentSelectedHovered: Color
@Composable
fun contentFor(state: ChipState) = rememberUpdatedState(
- state.chooseValue(
- normal = content,
- disabled = contentDisabled,
- focused = contentFocused,
- pressed = contentPressed,
- hovered = contentHovered,
- active = content
- )
+ if (state.isSelected) {
+ when {
+ !state.isEnabled -> contentSelectedDisabled
+ state.isPressed -> contentSelectedPressed
+ state.isFocused -> contentSelectedFocused
+ state.isHovered -> contentSelectedHovered
+ else -> contentSelected
+ }
+ } else {
+ when {
+ !state.isEnabled -> contentDisabled
+ state.isPressed -> contentPressed
+ state.isFocused -> contentFocused
+ state.isHovered -> contentHovered
+ else -> content
+ }
+ },
)
val border: Color
@@ -64,27 +92,41 @@ interface ChipColors {
val borderFocused: Color
val borderPressed: Color
val borderHovered: Color
+ val borderSelected: Color
+ val borderSelectedDisabled: Color
+ val borderSelectedPressed: Color
+ val borderSelectedFocused: Color
+ val borderSelectedHovered: Color
@Composable
fun borderFor(state: ChipState) = rememberUpdatedState(
- state.chooseValue(
- normal = border,
- disabled = borderDisabled,
- focused = borderFocused,
- pressed = borderPressed,
- hovered = borderHovered,
- active = border
- )
+ if (state.isSelected) {
+ when {
+ !state.isEnabled -> borderSelectedDisabled
+ state.isPressed && !IntelliJTheme.isSwingCompatMode -> borderSelectedPressed
+ state.isFocused -> borderSelectedFocused
+ state.isHovered && !IntelliJTheme.isSwingCompatMode -> borderSelectedHovered
+ else -> borderSelected
+ }
+ } else {
+ when {
+ !state.isEnabled -> borderDisabled
+ state.isPressed && !IntelliJTheme.isSwingCompatMode -> borderPressed
+ state.isFocused -> borderFocused
+ state.isHovered && !IntelliJTheme.isSwingCompatMode -> borderHovered
+ else -> border
+ }
+ },
)
}
@Stable
interface ChipMetrics {
- val minSize: DpSize
val cornerSize: CornerSize
val padding: PaddingValues
val borderWidth: Dp
+ val borderWidthSelected: Dp
}
val LocalChipStyle = staticCompositionLocalOf {
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/DropdownStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/DropdownStyling.kt
index d9e571c1fac2..6952b8da0fc0 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/DropdownStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/DropdownStyling.kt
@@ -31,21 +31,17 @@ interface DropdownColors {
val backgroundFocused: Color
val backgroundPressed: Color
val backgroundHovered: Color
- val backgroundWarning: Color
- val backgroundError: Color
@Composable
fun backgroundFor(state: DropdownState) = rememberUpdatedState(
- state.chooseValueWithOutline(
+ state.chooseValue(
normal = background,
disabled = backgroundDisabled,
focused = backgroundFocused,
pressed = backgroundPressed,
hovered = backgroundHovered,
- warning = backgroundWarning,
- error = backgroundError,
- active = background
- )
+ active = background,
+ ),
)
val content: Color
@@ -53,21 +49,17 @@ interface DropdownColors {
val contentFocused: Color
val contentPressed: Color
val contentHovered: Color
- val contentWarning: Color
- val contentError: Color
@Composable
fun contentFor(state: DropdownState) = rememberUpdatedState(
- state.chooseValueWithOutline(
+ state.chooseValue(
normal = content,
disabled = contentDisabled,
focused = contentFocused,
pressed = contentPressed,
hovered = contentHovered,
- warning = contentWarning,
- error = contentError,
- active = content
- )
+ active = content,
+ ),
)
val border: Color
@@ -75,21 +67,17 @@ interface DropdownColors {
val borderFocused: Color
val borderPressed: Color
val borderHovered: Color
- val borderWarning: Color
- val borderError: Color
@Composable
fun borderFor(state: DropdownState) = rememberUpdatedState(
- state.chooseValueWithOutline(
+ state.chooseValue(
normal = border,
disabled = borderDisabled,
focused = borderFocused,
pressed = borderPressed,
hovered = borderHovered,
- warning = borderWarning,
- error = borderError,
- active = border
- )
+ active = border,
+ ),
)
val iconTint: Color
@@ -97,27 +85,24 @@ interface DropdownColors {
val iconTintFocused: Color
val iconTintPressed: Color
val iconTintHovered: Color
- val iconTintWarning: Color
- val iconTintError: Color
@Composable
fun iconTintFor(state: DropdownState) = rememberUpdatedState(
- state.chooseValueWithOutline(
+ state.chooseValue(
normal = iconTint,
disabled = iconTintDisabled,
focused = iconTintFocused,
pressed = iconTintPressed,
hovered = iconTintHovered,
- warning = iconTintWarning,
- error = iconTintError,
- active = iconTint
- )
+ active = iconTint,
+ ),
)
}
@Stable
interface DropdownMetrics {
+ val arrowMinSize: DpSize
val minSize: DpSize
val cornerSize: CornerSize
val contentPadding: PaddingValues
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/HorizontalProgressBarStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/HorizontalProgressBarStyling.kt
index 492d02787e9c..0d210f234242 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/HorizontalProgressBarStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/HorizontalProgressBarStyling.kt
@@ -20,6 +20,7 @@ interface HorizontalProgressBarColors {
val track: Color
val progress: Color
+ val indeterminateBase: Color
val indeterminateHighlight: Color
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/InputFieldStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/InputFieldStyling.kt
index 99078bc9140c..221fdcc30b34 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/InputFieldStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/InputFieldStyling.kt
@@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
@@ -29,21 +28,17 @@ interface InputFieldColors {
val backgroundFocused: Color
val backgroundPressed: Color
val backgroundHovered: Color
- val backgroundWarning: Color
- val backgroundError: Color
@Composable
fun backgroundFor(state: InputFieldState) = rememberUpdatedState(
- state.chooseValueWithOutline(
+ state.chooseValue(
normal = background,
disabled = backgroundDisabled,
focused = backgroundFocused,
pressed = backgroundPressed,
hovered = backgroundHovered,
- warning = backgroundWarning,
- error = backgroundError,
- active = background
- )
+ active = background,
+ ),
)
val content: Color
@@ -51,21 +46,17 @@ interface InputFieldColors {
val contentFocused: Color
val contentPressed: Color
val contentHovered: Color
- val contentWarning: Color
- val contentError: Color
@Composable
fun contentFor(state: InputFieldState) = rememberUpdatedState(
- state.chooseValueWithOutline(
+ state.chooseValue(
normal = content,
disabled = contentDisabled,
focused = contentFocused,
pressed = contentPressed,
hovered = contentHovered,
- warning = contentWarning,
- error = contentError,
- active = content
- )
+ active = content,
+ ),
)
val border: Color
@@ -73,43 +64,35 @@ interface InputFieldColors {
val borderFocused: Color
val borderPressed: Color
val borderHovered: Color
- val borderWarning: Color
- val borderError: Color
@Composable
fun borderFor(state: InputFieldState) = rememberUpdatedState(
- state.chooseValueWithOutline(
+ state.chooseValue(
normal = border,
disabled = borderDisabled,
focused = borderFocused,
pressed = borderPressed,
hovered = borderHovered,
- warning = borderWarning,
- error = borderError,
- active = border
- )
+ active = border,
+ ),
)
- val cursor: Brush
- val cursorDisabled: Brush
- val cursorFocused: Brush
- val cursorPressed: Brush
- val cursorHovered: Brush
- val cursorWarning: Brush
- val cursorError: Brush
+ val caret: Color
+ val caretDisabled: Color
+ val caretFocused: Color
+ val caretPressed: Color
+ val caretHovered: Color
@Composable
- fun cursorFor(state: InputFieldState) = rememberUpdatedState(
- state.chooseValueWithOutline(
- normal = cursor,
- disabled = cursorDisabled,
- focused = cursorFocused,
- pressed = cursorPressed,
- hovered = cursorHovered,
- warning = cursorWarning,
- error = cursorError,
- active = cursor
- )
+ fun caretFor(state: InputFieldState) = rememberUpdatedState(
+ state.chooseValue(
+ normal = caret,
+ disabled = caretDisabled,
+ focused = caretFocused,
+ pressed = caretPressed,
+ hovered = caretHovered,
+ active = caret,
+ ),
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LazyTreeStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LazyTreeStyling.kt
index 974daa1fef9b..a0deaf0d01ef 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LazyTreeStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LazyTreeStyling.kt
@@ -8,10 +8,8 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.ResourceLoader
import androidx.compose.ui.unit.Dp
import org.jetbrains.jewel.foundation.tree.TreeElementState
-import org.jetbrains.jewel.painterResource
@Stable
interface LazyTreeStyle {
@@ -33,11 +31,6 @@ interface LazyTreeColors {
val contentSelected: Color
val contentSelectedFocused: Color
- val chevronTint: Color
- val chevronTintSelected: Color
- val chevronTintFocused: Color
- val chevronTintSelectedFocused: Color
-
@Composable
fun contentFor(state: TreeElementState) = rememberUpdatedState(
when {
@@ -45,17 +38,7 @@ interface LazyTreeColors {
state.isFocused -> contentFocused
state.isSelected -> contentSelected
else -> content
- }
- )
-
- @Composable
- fun chevronTintFor(state: TreeElementState) = rememberUpdatedState(
- when {
- state.isSelected && state.isFocused -> chevronTintSelectedFocused
- state.isFocused -> chevronTintFocused
- state.isSelected -> chevronTintSelected
- else -> chevronTint
- }
+ },
)
}
@@ -73,10 +56,12 @@ interface LazyTreeMetrics {
@Immutable
interface LazyTreeIcons {
- val nodeChevron: String
+ val nodeChevronCollapsed: StatefulPainterProvider
+ val nodeChevronExpanded: StatefulPainterProvider
@Composable
- fun nodeChevronPainter(resourceLoader: ResourceLoader) = painterResource(nodeChevron, resourceLoader)
+ fun nodeChevron(isExpanded: Boolean) =
+ if (isExpanded) nodeChevronExpanded else nodeChevronCollapsed
}
val LocalLazyTreeStyle = staticCompositionLocalOf {
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LinkStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LinkStyling.kt
index 23af066ae169..0499b58216e0 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LinkStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/LinkStyling.kt
@@ -39,12 +39,9 @@ interface LinkColors {
pressed = contentPressed,
hovered = contentHovered,
visited = contentVisited,
- active = content
- )
+ active = content,
+ ),
)
-
- val iconTint: Color
- val iconTintDisabled: Color
}
@Immutable
@@ -81,8 +78,8 @@ interface LinkTextStyles {
pressed = pressed,
hovered = hovered,
visited = visited,
- active = normal
- )
+ active = normal,
+ ),
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/MenuStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/MenuStyling.kt
index 15d708b3084a..450dc2e5d299 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/MenuStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/MenuStyling.kt
@@ -7,7 +7,6 @@ import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.staticCompositionLocalOf
-import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
@@ -24,7 +23,7 @@ interface MenuStyle {
@Immutable
interface MenuColors {
- val background: Brush
+ val background: Color
val border: Color
val shadow: Color
val itemColors: MenuItemColors
@@ -34,8 +33,7 @@ interface MenuColors {
interface MenuMetrics {
val cornerSize: CornerSize
- val margin: PaddingValues
- val padding: PaddingValues
+ val menuMargin: PaddingValues
val contentPadding: PaddingValues
val offset: DpOffset
val shadowSize: Dp
@@ -47,17 +45,17 @@ interface MenuMetrics {
@Stable
interface MenuItemMetrics {
- val cornerSize: CornerSize
- val padding: PaddingValues
+ val selectionCornerSize: CornerSize
+ val outerPadding: PaddingValues
val contentPadding: PaddingValues
val separatorPadding: PaddingValues
+ val separatorThickness: Dp
}
@Stable
interface SubmenuMetrics {
val offset: DpOffset
- val itemPadding: PaddingValues
}
@Immutable
@@ -77,8 +75,8 @@ interface MenuItemColors {
active = background,
focused = backgroundFocused,
pressed = backgroundPressed,
- hovered = backgroundHovered
- )
+ hovered = backgroundHovered,
+ ),
)
val content: Color
@@ -95,8 +93,8 @@ interface MenuItemColors {
focused = contentFocused,
pressed = contentPressed,
hovered = contentHovered,
- active = content
- )
+ active = content,
+ ),
)
val iconTint: Color
@@ -113,8 +111,8 @@ interface MenuItemColors {
focused = iconTintFocused,
pressed = iconTintPressed,
hovered = iconTintHovered,
- active = iconTint
- )
+ active = iconTint,
+ ),
)
val separator: Color
@@ -122,7 +120,8 @@ interface MenuItemColors {
@Immutable
interface MenuIcons {
- val submenuChevron: String
+
+ val submenuChevron: StatefulPainterProvider
}
val LocalMenuStyle = staticCompositionLocalOf {
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/RadioButtonStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/RadioButtonStyling.kt
index 2ca6fbcd6bbc..ed5b90620a21 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/RadioButtonStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/RadioButtonStyling.kt
@@ -36,65 +36,7 @@ interface RadioButtonColors {
state.isSelected -> contentSelected
state.isHovered -> contentHovered
else -> content
- }
- )
-
- val buttonColors: RadioButtonButtonColors
-}
-
-// TODO these should be used to tint the SVGs
-@Immutable
-interface RadioButtonButtonColors {
- val fill: Color
- val fillHovered: Color
- val fillDisabled: Color
- val fillSelected: Color
- val fillSelectedHovered: Color
- val fillSelectedDisabled: Color
-
- @Composable
- fun fillFor(state: RadioButtonState) = rememberUpdatedState(
- when {
- !state.isEnabled && state.isSelected -> fillSelectedDisabled
- !state.isEnabled -> fillDisabled
- state.isSelected && state.isHovered -> fillSelectedHovered
- state.isSelected -> fillSelected
- state.isHovered -> fillHovered
- else -> fill
- }
- )
-
- val border: Color
- val borderHovered: Color
- val borderDisabled: Color
- val borderSelected: Color
- val borderSelectedHovered: Color
- val borderSelectedDisabled: Color
-
- @Composable
- fun borderFor(state: RadioButtonState) = rememberUpdatedState(
- when {
- !state.isEnabled && state.isSelected -> borderSelectedDisabled
- !state.isEnabled -> borderDisabled
- state.isSelected && state.isHovered -> borderSelectedHovered
- state.isSelected -> borderSelected
- state.isHovered -> borderHovered
- else -> border
- }
- )
-
- val markSelected: Color
- val markSelectedHovered: Color
- val markSelectedDisabled: Color
-
- @Composable
- fun markFor(state: RadioButtonState) = rememberUpdatedState(
- when {
- !state.isSelected -> Color.Unspecified
- !state.isEnabled -> markSelectedDisabled
- state.isHovered -> markSelectedHovered
- else -> markSelected
- }
+ },
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ResourcePainterProvider.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ResourcePainterProvider.kt
index f183f555fb49..50b7116b7a24 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ResourcePainterProvider.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/ResourcePainterProvider.kt
@@ -15,7 +15,7 @@ import org.jetbrains.jewel.SvgLoader
import org.jetbrains.jewel.painterResource
@Immutable
-class ResourcePainterProvider(
+open class ResourcePainterProvider(
private val basePath: String,
private val svgLoader: SvgLoader,
private val prefixTokensProvider: (state: T) -> String = { "" },
@@ -26,9 +26,9 @@ class ResourcePainterProvider(
override fun getPainter(state: T, resourceLoader: ResourceLoader): State {
val isSvg = basePath.endsWith(".svg", ignoreCase = true)
val painter = if (isSvg) {
- svgLoader.loadSvgResource(basePath, resourceLoader) { patchPath(state, basePath) }
+ svgLoader.loadSvgResource(basePath, resourceLoader) { patchPath(state, basePath, resourceLoader) }
} else {
- val patchedPath = patchPath(state, basePath)
+ val patchedPath = patchPath(state, basePath, resourceLoader)
painterResource(patchedPath, resourceLoader)
}
@@ -36,7 +36,7 @@ class ResourcePainterProvider(
}
@Composable
- private fun patchPath(state: T, basePath: String): String = buildString {
+ protected open fun patchPath(state: T, basePath: String, resourceLoader: ResourceLoader): String = buildString {
append(basePath.substringBeforeLast('/', ""))
append('/')
append(basePath.substringBeforeLast('.').substringAfterLast('/'))
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TabStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TabStyling.kt
index 203b2cd38ec8..0fc114ffbfb9 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TabStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TabStyling.kt
@@ -69,9 +69,9 @@ interface TabColors {
focused = contentFocused,
pressed = contentPressed,
hovered = contentHovered,
- active = content
+ active = content,
)
- }
+ },
)
@Composable
@@ -84,7 +84,7 @@ interface TabColors {
state.isActive -> background
state.isSelected -> backgroundSelected
else -> background
- }
+ },
)
@Composable
@@ -97,9 +97,9 @@ interface TabColors {
focused = underlineFocused,
pressed = underlinePressed,
hovered = underlineHovered,
- active = underline
+ active = underline,
)
- }
+ },
)
}
@@ -123,9 +123,9 @@ interface TabContentAlpha {
focused = iconFocused,
pressed = iconPressed,
hovered = iconHovered,
- active = iconNormal
+ active = iconNormal,
)
- }
+ },
)
val labelNormal: Float
@@ -145,9 +145,9 @@ interface TabContentAlpha {
focused = labelFocused,
pressed = labelPressed,
hovered = labelHovered,
- active = labelNormal
+ active = labelNormal,
)
- }
+ },
)
}
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TextAreaStyling.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TextAreaStyling.kt
index edcc41314a9b..e0287b0bca4b 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TextAreaStyling.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/styling/TextAreaStyling.kt
@@ -1,33 +1,21 @@
package org.jetbrains.jewel.styling
-import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.TextStyle
-import org.jetbrains.jewel.InputFieldState
@Stable
interface TextAreaStyle : InputFieldStyle {
override val colors: TextAreaColors
override val metrics: InputFieldMetrics
- val hintTextStyle: TextStyle
}
@Immutable
interface TextAreaColors : InputFieldColors {
val placeholder: Color
- val hintContent: Color
- val hintContentDisabled: Color
-
- @Composable
- fun hintContentFor(state: InputFieldState) = rememberUpdatedState(
- if (state.isEnabled) hintContent else hintContentDisabled
- )
}
val LocalTextAreaStyle = staticCompositionLocalOf {
diff --git a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/themes/PaletteMapperFactory.kt b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/themes/PaletteMapperFactory.kt
index df2162dabcd4..d22635b3273b 100644
--- a/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/themes/PaletteMapperFactory.kt
+++ b/platform/jewel/core/src/main/kotlin/org/jetbrains/jewel/themes/PaletteMapperFactory.kt
@@ -55,7 +55,7 @@ object PaletteMapperFactory {
"Checkbox.Focus.Thin.Selected" to "#ACCFF7",
"Checkbox.Focus.Thin.Selected.Dark" to "#466D94",
"Tree.iconColor" to "#808080",
- "Tree.iconColor.Dark" to "#AFB1B3"
+ "Tree.iconColor.Dark" to "#AFB1B3",
)
fun create(
diff --git a/platform/jewel/detekt.yml b/platform/jewel/detekt.yml
index 9118bc55da7f..44a7553c8ba0 100644
--- a/platform/jewel/detekt.yml
+++ b/platform/jewel/detekt.yml
@@ -104,7 +104,9 @@ style:
includeLineWrapping: false
ForbiddenComment:
active: true
- values: [ 'STOPSHIP' ]
+ comments:
+ - value: 'STOPSHIP'
+ reason: 'Forbidden STOPSHIP marker in comment, please address before shipping'
allowedPatterns: ''
LoopWithTooManyJumpStatements:
active: true
diff --git a/platform/jewel/gradle/libs.versions.toml b/platform/jewel/gradle/libs.versions.toml
index 804883fe1ad0..29ddb9fea63e 100644
--- a/platform/jewel/gradle/libs.versions.toml
+++ b/platform/jewel/gradle/libs.versions.toml
@@ -1,23 +1,20 @@
[versions]
-composeDesktop = "1.5.0-dev1136"
-coroutines = "1.6.4"
-detekt = "1.22.0"
+composeDesktop = "1.5.0-rc02"
+coroutines = "1.7.3"
+detekt = "1.23.1"
idea = "232.8660.185"
-ideaGradlePlugin = "1.13.0"
+ideaGradlePlugin = "1.15.0"
javaSarif = "2.0"
kotlinSarif = "0.4.0"
-jna = "5.10.0"
-kotlin = "1.8.20"
+kotlin = "1.8.21"
dokka = "1.8.20"
-kotlinterGradlePlugin = "3.12.0"
+kotlinterGradlePlugin = "3.16.0"
kotlinxSerialization = "1.5.1"
kotlinpoet = "1.14.2"
[libraries]
-compose-components-splitpane = { module = "org.jetbrains.compose.components:components-splitpane", version.ref = "composeDesktop" }
javaSarif = { module = "com.contrastsecurity:java-sarif", version.ref = "javaSarif" }
kotlinSarif = { module = "io.github.detekt.sarif4k:sarif4k", version.ref = "kotlinSarif" }
-jna = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
ij-platform-ide-core = { module = "com.jetbrains.intellij.platform:ide-core", version.ref = "idea" }
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/Bridge.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/Bridge.kt
index ab8cf7933518..89b18c1c3e25 100644
--- a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/Bridge.kt
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/Bridge.kt
@@ -2,52 +2,42 @@
package org.jetbrains.jewel.bridge
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.platform.Typeface
-import androidx.compose.ui.unit.TextUnit
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.intellij.ide.ui.LafManager
import com.intellij.ide.ui.LafManagerListener
import com.intellij.openapi.application.Application
import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.diagnostic.Logger
+import com.intellij.util.messages.MessageBus
import com.intellij.util.messages.SimpleMessageBusConnection
import com.intellij.util.messages.Topic
-import com.intellij.util.ui.DirProvider
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.map
-import org.jetbrains.skiko.toSkikoTypeface
-import javax.swing.UIManager
-import java.awt.Color as AwtColor
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
internal val IntelliJApplication: Application
get() = ApplicationManager.getApplication()
-internal val Application.intellijThemeFlow
- get() = lookAndFeelFlow.map { ObtainIntelliJTheme() }
-
-internal val Application.lookAndFeelFlow: Flow
- get() = messageBusFlow(LafManagerListener.TOPIC, { LafManager.getInstance()!! }) {
- LafManagerListener { trySend(it) }
+private val Application.lookAndFeelFlow: Flow
+ get() = messageBus.flow(LafManagerListener.TOPIC) {
+ LafManagerListener { trySend(Unit) }
}
-internal fun Application.messageBusFlow(
+internal fun Application.lookAndFeelChangedFlow(
+ scope: CoroutineScope,
+ sharingStarted: SharingStarted = SharingStarted.Eagerly,
+): Flow =
+ lookAndFeelFlow
+ .onStart { emit(Unit) }
+ .shareIn(scope, sharingStarted, replay = 1)
+
+internal fun MessageBus.flow(
topic: Topic,
- initialValue: (suspend () -> K)? = null,
- @BuilderInference listener: ProducerScope.() -> L
+ listener: ProducerScope.() -> L,
): Flow = callbackFlow {
- initialValue?.let { send(it()) }
- val connection: SimpleMessageBusConnection = messageBus.simpleConnect()
+ val connection: SimpleMessageBusConnection = simpleConnect()
connection.subscribe(topic, listener())
awaitClose { connection.disconnect() }
}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeGlobalColors.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeGlobalColors.kt
new file mode 100644
index 000000000000..24dfbb8760d0
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeGlobalColors.kt
@@ -0,0 +1,136 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.ui.graphics.Color
+import org.jetbrains.jewel.BorderColors
+import org.jetbrains.jewel.GlobalColors
+import org.jetbrains.jewel.OutlineColors
+
+@Immutable
+internal class BridgeGlobalColors(
+ override val borders: BorderColors,
+ override val outlines: OutlineColors,
+ @SwingLafKey("*.infoForeground") override val infoContent: Color,
+) : GlobalColors {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as BridgeGlobalColors
+
+ if (borders != other.borders) return false
+ if (outlines != other.outlines) return false
+ if (infoContent != other.infoContent) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = borders.hashCode()
+ result = 31 * result + outlines.hashCode()
+ result = 31 * result + infoContent.hashCode()
+ return result
+ }
+
+ override fun toString(): String =
+ "BridgeGlobalColors(borders=$borders, outlines=$outlines, infoContent=$infoContent)"
+
+ companion object {
+
+ fun readFromLaF() = BridgeGlobalColors(
+ borders = BridgeBorderColors.readFromLaF(),
+ outlines = BridgeOutlineColors.readFromLaF(),
+ infoContent = retrieveColorOrUnspecified("*.infoForeground"),
+ )
+ }
+}
+
+@Immutable
+internal class BridgeBorderColors(
+ @SwingLafKey("Component.borderColor") override val normal: Color,
+ @SwingLafKey("Component.focusedBorderColor") override val focused: Color,
+ @SwingLafKey("*.disabledBorderColor") override val disabled: Color,
+) : BorderColors {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as BridgeBorderColors
+
+ if (normal != other.normal) return false
+ if (focused != other.focused) return false
+ if (disabled != other.disabled) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = normal.hashCode()
+ result = 31 * result + focused.hashCode()
+ result = 31 * result + disabled.hashCode()
+ return result
+ }
+
+ override fun toString(): String =
+ "BridgeBorderColors(normal=$normal, focused=$focused, disabled=$disabled)"
+
+ companion object {
+
+ fun readFromLaF() = BridgeBorderColors(
+ normal = retrieveColorOrUnspecified("Component.borderColor"),
+ focused = retrieveColorOrUnspecified("Component.focusedBorderColor"),
+ disabled = retrieveColorOrUnspecified("*.disabledBorderColor"),
+ )
+ }
+}
+
+@Immutable
+internal class BridgeOutlineColors(
+ @SwingLafKey("*.focusColor") override val focused: Color,
+ @SwingLafKey("Component.warningFocusColor") override val focusedWarning: Color,
+ @SwingLafKey("Component.errorFocusColor") override val focusedError: Color,
+ @SwingLafKey("Component.inactiveWarningFocusColor") override val warning: Color,
+ @SwingLafKey("Component.inactiveErrorFocusColor") override val error: Color,
+) : OutlineColors {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as BridgeOutlineColors
+
+ if (focused != other.focused) return false
+ if (focusedWarning != other.focusedWarning) return false
+ if (focusedError != other.focusedError) return false
+ if (warning != other.warning) return false
+ if (error != other.error) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = focused.hashCode()
+ result = 31 * result + focusedWarning.hashCode()
+ result = 31 * result + focusedError.hashCode()
+ result = 31 * result + warning.hashCode()
+ result = 31 * result + error.hashCode()
+ return result
+ }
+
+ override fun toString(): String =
+ "BridgeOutlineColors(focused=$focused, focusedWarning=$focusedWarning, focusedError=$focusedError, " +
+ "warning=$warning, error=$error)"
+
+ companion object {
+
+ fun readFromLaF() = BridgeOutlineColors(
+ focused = retrieveColorOrUnspecified("*.focusColor"),
+ focusedWarning = retrieveColorOrUnspecified("Component.warningFocusColor"),
+ focusedError = retrieveColorOrUnspecified("Component.errorFocusColor"),
+ warning = retrieveColorOrUnspecified("Component.inactiveWarningFocusColor"),
+ error = retrieveColorOrUnspecified("Component.inactiveErrorFocusColor"),
+ )
+ }
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeGlobalMetrics.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeGlobalMetrics.kt
new file mode 100644
index 000000000000..b5e5722d1f67
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeGlobalMetrics.kt
@@ -0,0 +1,35 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.ui.unit.Dp
+import com.intellij.ide.ui.laf.darcula.DarculaUIUtil
+import org.jetbrains.jewel.GlobalMetrics
+
+@Immutable
+internal class BridgeGlobalMetrics(
+ override val outlineWidth: Dp,
+) : GlobalMetrics {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as BridgeGlobalMetrics
+
+ if (outlineWidth != other.outlineWidth) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int = outlineWidth.hashCode()
+
+ override fun toString(): String =
+ "BridgeGlobalMetrics(outlineWidth=$outlineWidth)"
+
+ companion object {
+
+ fun readFromLaF() = BridgeGlobalMetrics(
+ outlineWidth = DarculaUIUtil.BW.dp,
+ )
+ }
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIconData.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIconData.kt
new file mode 100644
index 000000000000..120646adfd4f
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIconData.kt
@@ -0,0 +1,38 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.runtime.Immutable
+import org.jetbrains.jewel.IntelliJThemeIconData
+
+@Immutable
+internal class BridgeIconData(
+ override val iconOverrides: Map,
+ override val colorPalette: Map,
+) : IntelliJThemeIconData {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as BridgeIconData
+
+ if (iconOverrides != other.iconOverrides) return false
+ if (colorPalette != other.colorPalette) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = iconOverrides.hashCode()
+ result = 31 * result + colorPalette.hashCode()
+ return result
+ }
+
+ override fun toString(): String =
+ "BridgeIconData(iconOverrides=$iconOverrides, colorPalette=$colorPalette)"
+
+ companion object {
+
+ // TODO retrieve icon data from Swing
+ fun readFromLaF() = BridgeIconData(emptyMap(), emptyMap())
+ }
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIntelliJTheme.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIntelliJTheme.kt
deleted file mode 100644
index 5935468e8881..000000000000
--- a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIntelliJTheme.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.jetbrains.jewel.bridge
-
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.platform.Typeface
-import androidx.compose.ui.unit.TextUnit
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.intellij.openapi.diagnostic.Logger
-import com.intellij.ui.NewUI
-import com.intellij.util.ui.DirProvider
-import org.jetbrains.jewel.IntelliJTheme
-import org.jetbrains.skiko.toSkikoTypeface
-import javax.swing.UIManager
-
-private val logger = Logger.getInstance("JewelBridge")
-
-private val dirProvider = DirProvider()
-
-internal fun ObtainIntelliJTheme(): IntelliJTheme {
- val isIntUi = NewUI.isEnabled()
-
- if (!isIntUi) {
- // TODO return Darcula/IntelliJ Light theme instead
- logger.warn("Darcula LaF (aka \"old UI\" are not supported yet, falling back to Int UI")
- }
-
- return bridgeIntUi()
-}
-
-fun java.awt.Color.toComposeColor() = Color(
- red = red,
- green = green,
- blue = blue,
- alpha = alpha
-)
-
-internal fun retrieveColorOrNull(key: String) =
- UIManager.getColor(key)?.toComposeColor()
-
-internal fun retrieveColorOrUnspecified(key: String): Color {
- val color = retrieveColorOrNull(key)
- if (color == null) {
- logger.warn("Color with key \"$key\" not found, fallback to 'Color.Unspecified'")
- }
- return color ?: Color.Unspecified
-}
-
-internal fun retrieveColorsOrUnspecified(vararg keys: String) = keys.map { retrieveColorOrUnspecified(it) }
-
-// Based on LafIconLookup#findIcon
-// TODO inject additional logic from ImageLoader#addFileNameVariant to support loading the right icon
-// variants ([_dark], [@2x], [_stroke])
-internal fun lookupIJSvgIcon(
- name: String,
- selected: Boolean = false,
- focused: Boolean = false,
- enabled: Boolean = true,
- editable: Boolean = false,
- pressed: Boolean = false
-): @Composable () -> Painter {
- var key = name
- if (editable) {
- key += "Editable"
- }
- if (selected) {
- key += "Selected"
- }
-
- when {
- pressed -> key += "Pressed"
- focused -> key += "Focused"
- !enabled -> key += "Disabled"
- }
-
- // for Mac blue theme and other LAFs use default directory icons
- val dir = dirProvider.dir()
- val path = "$dir$key.svg"
-
- return {
- rememberSvgResource(path.removePrefix("/"), dirProvider.javaClass.classLoader)
- }
-}
-
-internal fun retrieveIntAsDp(key: String) = UIManager.getInt(key).dp
-
-internal fun retrieveInsetsAsPaddingValues(key: String) =
- UIManager.getInsets(key)
- .let { PaddingValues(it.left.dp, it.top.dp, it.right.dp, it.bottom.dp) }
-
-internal suspend fun retrieveFont(
- key: String,
- color: Color = Color.Unspecified,
- lineHeight: TextUnit = TextUnit.Unspecified
-): TextStyle {
- val font = UIManager.getFont(key) ?: error("Font with key \"$key\" not found, fallback to 'Typeface.makeDefault()'")
- return with(font) {
- val typeface = toSkikoTypeface() ?: org.jetbrains.skia.Typeface.makeDefault().also {
- logger.warn("Unable to convert font ${font.fontName} into a Skiko typeface, fallback to 'Typeface.makeDefault()'")
- }
- TextStyle(
- color = color,
- fontSize = size.sp,
- fontWeight = FontWeight.Normal,
- fontFamily = FontFamily(Typeface(typeface)),
- // todo textDecoration might be defined in the awt theme
- lineHeight = lineHeight
- )
- }
-}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeThemeColorPalette.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeThemeColorPalette.kt
new file mode 100644
index 000000000000..88d2218b0c5b
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeThemeColorPalette.kt
@@ -0,0 +1,95 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.ui.graphics.Color
+import com.intellij.openapi.diagnostic.Logger
+import org.jetbrains.jewel.themes.intui.core.IntUiThemeColorPalette
+
+private val logger = Logger.getInstance("BridgeThemeColorPalette")
+
+@Immutable
+class BridgeThemeColorPalette(
+ private val grey: List,
+ private val blue: List,
+ private val green: List,
+ private val red: List,
+ private val yellow: List,
+ private val orange: List,
+ private val purple: List,
+ private val teal: List,
+) : IntUiThemeColorPalette {
+
+ override fun grey(): List = grey
+
+ override fun grey(index: Int): Color = grey[index - 1]
+
+ override fun blue(): List = blue
+
+ override fun blue(index: Int): Color = blue[index - 1]
+
+ override fun green(): List = green
+
+ override fun green(index: Int): Color = green[index - 1]
+
+ override fun red(): List = red
+
+ override fun red(index: Int): Color = red[index - 1]
+
+ override fun yellow(): List = yellow
+
+ override fun yellow(index: Int): Color = yellow[index - 1]
+
+ override fun orange(): List = orange
+
+ override fun orange(index: Int): Color = orange[index - 1]
+
+ override fun purple(): List = purple
+
+ override fun purple(index: Int): Color = purple[index - 1]
+
+ override fun teal(): List = teal
+
+ override fun teal(index: Int): Color = teal[index - 1]
+
+ companion object {
+
+ fun readFromLaF() = BridgeThemeColorPalette(
+ grey = readPaletteColors("Grey"),
+ blue = readPaletteColors("Blue"),
+ green = readPaletteColors("Green"),
+ red = readPaletteColors("Red"),
+ yellow = readPaletteColors("Yellow"),
+ orange = readPaletteColors("Orange"),
+ purple = readPaletteColors("Purple"),
+ teal = readPaletteColors("Teal"),
+ )
+
+ private fun readPaletteColors(colorName: String): List {
+ val defaults = uiDefaults
+ val allKeys = defaults.keys
+ val colorNameKeyPrefix = "ColorPalette.$colorName"
+ val colorNameKeyPrefixLength = colorNameKeyPrefix.length
+
+ val lastColorIndex = allKeys.asSequence()
+ .filterIsInstance(String::class.java)
+ .filter { it.startsWith(colorNameKeyPrefix) }
+ .mapNotNull {
+ val afterName = it.substring(colorNameKeyPrefixLength)
+ afterName.toIntOrNull()
+ }
+ .maxOrNull() ?: return emptyList()
+
+ return buildList {
+ for (i in 1..lastColorIndex) {
+ val value = defaults["$colorNameKeyPrefix$i"] as? java.awt.Color
+ if (value == null) {
+ logger.error("Unable to find color value for palette key '$colorNameKeyPrefix$i'")
+ continue
+ }
+
+ add(value.toComposeColor())
+ }
+ }
+ }
+ }
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeUtils.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeUtils.kt
new file mode 100644
index 000000000000..56f3afd222c2
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeUtils.kt
@@ -0,0 +1,169 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.TileMode
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.platform.Typeface
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.ui.JBColor
+import com.intellij.util.ui.JBValue
+import org.jetbrains.jewel.IntelliJThemeIconData
+import org.jetbrains.jewel.InteractiveComponentState
+import org.jetbrains.jewel.SvgLoader
+import org.jetbrains.jewel.styling.StatefulPainterProvider
+import org.jetbrains.skiko.DependsOnJBR
+import org.jetbrains.skiko.awt.font.AwtFontManager
+import org.jetbrains.skiko.toSkikoTypefaceOrNull
+import javax.swing.UIManager
+
+private val logger = Logger.getInstance("JewelBridge")
+
+fun java.awt.Color.toComposeColor() = Color(
+ red = red,
+ green = green,
+ blue = blue,
+ alpha = alpha,
+)
+
+fun java.awt.Color?.toComposeColorOrUnspecified() = this?.toComposeColor() ?: Color.Unspecified
+
+@Suppress("UnstableApiUsage")
+internal fun retrieveColorOrNull(key: String) =
+ JBColor.namedColor(key)
+ .takeUnless { it.name == "NAMED_COLOR_FALLBACK_MARKER" }
+ ?.toComposeColor()
+
+internal fun retrieveColorOrUnspecified(key: String): Color {
+ val color = retrieveColorOrNull(key)
+ if (color == null) {
+ logger.warn("Color with key \"$key\" not found, fallback to 'Color.Unspecified'")
+ }
+ return color ?: Color.Unspecified
+}
+
+internal fun retrieveColorsOrUnspecified(vararg keys: String) = keys.map { retrieveColorOrUnspecified(it) }
+
+internal fun List.createVerticalBrush(
+ startY: Float = 0.0f,
+ endY: Float = Float.POSITIVE_INFINITY,
+ tileMode: TileMode = TileMode.Clamp,
+): Brush {
+ if (isEmpty()) return SolidColor(Color.Transparent)
+ if (size == 1) return SolidColor(first())
+
+ // Optimization: use a cheaper SolidColor if all colors are identical
+ if (all { it == first() }) SolidColor(first())
+
+ return Brush.verticalGradient(this, startY, endY, tileMode)
+}
+
+internal fun retrieveIntAsDp(key: String): Dp {
+ val rawValue = UIManager.get(key)
+ if (rawValue is Int) rawValue.dp
+
+ keyNotFound(key, "Int")
+}
+
+internal fun retrieveIntAsDpOrUnspecified(key: String) =
+ try {
+ retrieveIntAsDp(key)
+ } catch (ignored: JewelBridgeException) {
+ Dp.Unspecified
+ }
+
+internal fun retrieveInsetsAsPaddingValues(key: String) =
+ UIManager.getInsets(key)
+ ?.let { PaddingValues(it.left.dp, it.top.dp, it.right.dp, it.bottom.dp) }
+ ?: keyNotFound(key, "Insets")
+
+internal fun retrieveArcAsCornerSize(key: String) =
+ CornerSize(retrieveIntAsDp(key) / 2)
+
+internal fun retrieveArcAsCornerSizeWithFallbacks(vararg keys: String): CornerSize {
+ for (key in keys) {
+ val rawValue = UIManager.get(key)
+ if (rawValue is Int) {
+ val cornerSize = rawValue.dp
+
+ // Swing uses arcs, which are a diameter length, but we need a radius
+ return CornerSize(cornerSize / 2)
+ }
+ }
+
+ keysNotFound(keys.toList(), "Int")
+}
+
+@OptIn(DependsOnJBR::class)
+private val awtFontManager = AwtFontManager()
+
+internal suspend fun retrieveTextStyle(fontKey: String, colorKey: String? = null): TextStyle {
+ val baseColor = colorKey?.let { retrieveColorOrUnspecified(colorKey) } ?: Color.Unspecified
+ return retrieveTextStyle(fontKey, color = baseColor)
+}
+
+@OptIn(DependsOnJBR::class)
+internal suspend fun retrieveTextStyle(
+ key: String,
+ color: Color = Color.Unspecified,
+ lineHeight: TextUnit = TextUnit.Unspecified,
+): TextStyle {
+ val font = UIManager.getFont(key) ?: keyNotFound(key, "Font")
+
+ return with(font) {
+ val typeface = toSkikoTypefaceOrNull(awtFontManager)
+ ?: org.jetbrains.skia.Typeface.makeDefault()
+ .also {
+ logger.warn(
+ "Unable to convert font ${font.fontName} into a Skiko typeface, " +
+ "fallback to 'Typeface.makeDefault()'",
+ )
+ }
+
+ TextStyle(
+ color = color,
+ fontSize = size.sp,
+ fontWeight = FontWeight.Normal,
+ fontFamily = FontFamily(Typeface(typeface)),
+ // todo textDecoration might be defined in the awt theme
+ lineHeight = lineHeight,
+ )
+ }
+}
+
+internal val JBValue.dp
+ get() = unscaled.dp
+
+internal fun TextStyle.derive(sizeDelta: Float, weight: FontWeight? = fontWeight, color: Color = toSpanStyle().color) =
+ copy(fontSize = fontSize - sizeDelta, fontWeight = weight, color = color)
+
+internal operator fun TextUnit.minus(delta: Float) = plus(-delta)
+
+internal operator fun TextUnit.plus(delta: Float) =
+ when {
+ isSp -> TextUnit(value + delta, type)
+ isEm -> TextUnit(value + delta, type)
+ else -> this
+ }
+
+internal fun retrieveIcon(
+ baseIconPath: String,
+ iconData: IntelliJThemeIconData,
+ svgLoader: SvgLoader,
+ prefixTokensProvider: (state: T) -> String = { "" },
+ suffixTokensProvider: (state: T) -> String = { "" },
+): StatefulPainterProvider = IntelliJResourcePainterProvider(
+ basePath = iconData.iconOverrides[baseIconPath] ?: baseIconPath,
+ svgLoader,
+ prefixTokensProvider,
+ suffixTokensProvider,
+)
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/ComposePanel.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/ComposePanel.kt
new file mode 100644
index 000000000000..bad0ccbb5caf
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/ComposePanel.kt
@@ -0,0 +1,28 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.awt.ComposePanel
+import com.intellij.openapi.wm.ToolWindow
+
+fun ToolWindow.addComposePanel(
+ tabDisplayName: String,
+ isLockable: Boolean = true,
+ content: @Composable ComposePanel.() -> Unit,
+) = ComposePanel {
+ content()
+}.also { contentManager.addContent(contentManager.factory.createContent(it, tabDisplayName, isLockable)) }
+
+internal fun ComposePanel(
+ height: Int = 800,
+ width: Int = 800,
+ y: Int = 0,
+ x: Int = 0,
+ content: @Composable ComposePanel.() -> Unit,
+): ComposePanel {
+ val panel = ComposePanel()
+ panel.setBounds(x, y, width, height)
+ panel.setContent {
+ panel.content()
+ }
+ return panel
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntUiBridge.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntUiBridge.kt
index a931a89e0a5a..7939a5374b8d 100644
--- a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntUiBridge.kt
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntUiBridge.kt
@@ -1,212 +1,873 @@
package org.jetbrains.jewel.bridge
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.ui.graphics.Brush
+import androidx.compose.foundation.shape.CornerSize
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.state.ToggleableState
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.takeOrElse
+import com.intellij.ide.ui.laf.darcula.DarculaUIUtil
+import com.intellij.ide.ui.laf.darcula.ui.DarculaCheckBoxUI
+import com.intellij.ide.ui.laf.intellij.IdeaPopupMenuUI
import com.intellij.openapi.diagnostic.Logger
-import com.intellij.util.ui.StartupUiUtil
-import org.jetbrains.jewel.ButtonDefaults
-import org.jetbrains.jewel.CheckboxDefaults
-import org.jetbrains.jewel.IntelliJColors
-import org.jetbrains.jewel.IntelliJTheme
-import org.jetbrains.jewel.buttonColors
-import org.jetbrains.jewel.checkBoxColors
-import org.jetbrains.jewel.foundation.Stroke
-import org.jetbrains.jewel.themes.intui.core.IntUiColorPalette
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.ui.JBColor
+import com.intellij.util.ui.DirProvider
+import com.intellij.util.ui.JBUI
+import com.intellij.util.ui.NamedColorUtil
+import com.intellij.util.ui.StatusText
+import org.jetbrains.jewel.CheckboxState
+import org.jetbrains.jewel.IntelliJComponentStyling
+import org.jetbrains.jewel.IntelliJThemeIconData
+import org.jetbrains.jewel.SvgLoader
+import org.jetbrains.jewel.styling.InputFieldStyle
+import org.jetbrains.jewel.themes.intui.core.IntUiThemeDefinition
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiButtonColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiButtonMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiButtonStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiCheckboxColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiCheckboxIcons
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiCheckboxMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiCheckboxStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiChipColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiChipMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiChipStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiDropdownColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiDropdownIcons
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiDropdownMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiDropdownStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiGroupHeaderColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiGroupHeaderMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiGroupHeaderStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiHorizontalProgressBarColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiHorizontalProgressBarMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiHorizontalProgressBarStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLabelledTextFieldColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLabelledTextFieldMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLabelledTextFieldStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLabelledTextFieldTextStyles
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLazyTreeColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLazyTreeIcons
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLazyTreeMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLazyTreeStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLinkColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLinkIcons
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLinkMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLinkStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiLinkTextStyles
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiMenuColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiMenuIcons
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiMenuItemColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiMenuItemMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiMenuMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiMenuStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiRadioButtonColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiRadioButtonIcons
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiRadioButtonMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiRadioButtonStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiScrollbarColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiScrollbarMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiScrollbarStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiSubmenuMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTabColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTabContentAlpha
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTabIcons
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTabMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTabStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTextAreaColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTextAreaMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTextAreaStyle
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTextFieldColors
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTextFieldMetrics
+import org.jetbrains.jewel.themes.intui.standalone.styling.IntUiTextFieldStyle
import javax.swing.UIManager
+import kotlin.time.Duration.Companion.milliseconds
private val logger = Logger.getInstance("JewelIntUiBridge")
-private val uiDefaults
+internal val uiDefaults
get() = UIManager.getDefaults()
-internal fun bridgeIntUi(): IntelliJTheme {
- val isDark = StartupUiUtil.isUnderDarcula()
-
- return IntUiBridgeTheme(
- isDark,
- readIntUiColorPalette(isDark),
- readIntelliJColors(),
- readButtonDefaults(),
- readCheckboxDefaults(),
- groupHeaderDefaults,
- linkDefaults,
- textFieldDefaults,
- labelledTextFieldDefaults,
- textAreaDefaults,
- radioButtonDefaults,
- dropdownDefaults,
- contextMenuDefaults,
- defaultTextStyle,
- treeDefaults,
- chipDefaults,
- scrollThumbDefaults,
- progressBarDefaults,
- )
+internal suspend fun createBridgeIntUiDefinition(): IntUiThemeDefinition {
+ val textStyle = retrieveTextStyle("Label.font", "Label.foreground")
+ return createBridgeIntUiDefinition(textStyle)
}
-private fun readIntUiColorPalette(isDark: Boolean) =
- IntUiColorPalette(
+internal fun createBridgeIntUiDefinition(textStyle: TextStyle): IntUiThemeDefinition {
+ val isDark = !JBColor.isBright()
+
+ logger.debug("Obtaining Int UI theme definition from Swing...")
+
+ return IntUiThemeDefinition(
isDark = isDark,
- grey = readPaletteColors("Grey"),
- blue = readPaletteColors("Blue"),
- green = readPaletteColors("Green"),
- red = readPaletteColors("Red"),
- yellow = readPaletteColors("Yellow"),
- orange = readPaletteColors("Orange"),
- purple = readPaletteColors("Purple"),
- teal = readPaletteColors("Teal"),
+ globalColors = BridgeGlobalColors.readFromLaF(),
+ colorPalette = BridgeThemeColorPalette.readFromLaF(),
+ iconData = BridgeIconData.readFromLaF(),
+ globalMetrics = BridgeGlobalMetrics.readFromLaF(),
+ defaultTextStyle = textStyle,
)
-
-private fun readPaletteColors(colorName: String): List {
- val defaults = uiDefaults
- val allKeys = defaults.keys
- val colorNameLength = colorName.length
-
- val lastColorIndex = allKeys.asSequence()
- .filterIsInstance(String::class.java)
- .filter { it.startsWith(colorName) }
- .mapNotNull {
- val afterName = it.substring(colorNameLength)
- afterName.toIntOrNull()
- }
- .max()
-
- return buildList {
- for (i in 1..lastColorIndex) {
- val value = defaults["$colorName$i"] as? java.awt.Color
- if (value == null) {
- logger.error("Unable to find color value for palette key '$colorName$i'")
- continue
- }
-
- add(value.toComposeColor())
- }
- }
}
-private fun readIntelliJColors() = IntelliJColors(
- foreground = retrieveColorOrUnspecified("Label.foreground"),
- background = retrieveColorOrUnspecified("Panel.background"),
- borderColor = retrieveColorOrUnspecified("Component.borderColor"),
- disabledForeground = retrieveColorOrUnspecified("Label.disabledForeground"),
- disabledBorderColor = retrieveColorOrUnspecified("Component.disabledBorderColor"),
+internal suspend fun createSwingIntUiComponentStyling(
+ theme: IntUiThemeDefinition,
+ svgLoader: SvgLoader,
+): IntelliJComponentStyling = createSwingIntUiComponentStyling(
+ theme = theme,
+ svgLoader = svgLoader,
+ textAreaTextStyle = retrieveTextStyle("TextArea.font", "TextArea.foreground"),
+ textFieldTextStyle = retrieveTextStyle("TextField.font", "TextField.foreground"),
+ dropdownTextStyle = retrieveTextStyle("ComboBox.font"),
+ labelTextStyle = retrieveTextStyle("Label.font"),
+ linkTextStyle = retrieveTextStyle("Label.font"),
)
-// Hardcoded values come from DarculaButtonUI (they may be derived from multiple values)
-private fun readButtonDefaults(): ButtonDefaults {
- val backgroundBrush = Brush.verticalGradient(retrieveColorsOrUnspecified("Button.startBackground", "Button.endBackground"))
- val contentColor = retrieveColorOrUnspecified("Button.foreground")
- val borderStroke = Stroke(
- width = 1.dp,
- brush = Brush.verticalGradient(retrieveColorsOrUnspecified("Button.startBorderColor", "Button.endBorderColor")),
- alignment = Stroke.Alignment.Center
+internal fun createSwingIntUiComponentStyling(
+ theme: IntUiThemeDefinition,
+ svgLoader: SvgLoader,
+ textFieldTextStyle: TextStyle,
+ textAreaTextStyle: TextStyle,
+ dropdownTextStyle: TextStyle,
+ labelTextStyle: TextStyle,
+ linkTextStyle: TextStyle,
+): IntelliJComponentStyling {
+ logger.debug("Obtaining Int UI component styling from Swing...")
+
+ val textFieldStyle = readTextFieldStyle(textFieldTextStyle)
+ val menuStyle = readMenuStyle(theme.iconData, svgLoader)
+
+ return IntelliJComponentStyling(
+ checkboxStyle = readCheckboxStyle(theme.iconData, svgLoader),
+ chipStyle = readChipStyle(),
+ defaultButtonStyle = readDefaultButtonStyle(),
+ defaultTabStyle = readDefaultTabStyle(theme.iconData, svgLoader),
+ dropdownStyle = readDropdownStyle(theme.iconData, svgLoader, menuStyle, dropdownTextStyle),
+ editorTabStyle = readEditorTabStyle(theme.iconData, svgLoader),
+ groupHeaderStyle = readGroupHeaderStyle(),
+ horizontalProgressBarStyle = readHorizontalProgressBarStyle(),
+ labelledTextFieldStyle = readLabelledTextFieldStyle(textFieldStyle, labelTextStyle),
+ lazyTreeStyle = readLazyTreeStyle(theme.iconData, svgLoader),
+ linkStyle = readLinkStyle(theme.iconData, svgLoader, linkTextStyle),
+ menuStyle = menuStyle,
+ outlinedButtonStyle = readOutlinedButtonStyle(),
+ radioButtonStyle = readRadioButtonStyle(theme.iconData, svgLoader),
+ scrollbarStyle = readScrollbarStyle(theme.isDark),
+ textAreaStyle = readTextAreaStyle(textAreaTextStyle, textFieldStyle.metrics),
+ textFieldStyle = textFieldStyle,
)
- val haloStroke = Stroke(
- width = retrieveIntAsDp("Component.focusWidth"),
- color = retrieveColorOrUnspecified("Component.focusColor"),
- alignment = Stroke.Alignment.Outside
+}
+
+private fun readDefaultButtonStyle(): IntUiButtonStyle {
+ val normalBackground =
+ retrieveColorsOrUnspecified(
+ "Button.default.startBackground",
+ "Button.default.endBackground",
+ ).createVerticalBrush()
+ val normalContent = retrieveColorOrUnspecified("Button.default.foreground")
+ val normalBorder =
+ retrieveColorsOrUnspecified("Button.default.startBorderColor", "Button.default.endBorderColor")
+ .createVerticalBrush()
+
+ val colors = IntUiButtonColors(
+ background = normalBackground,
+ backgroundDisabled = SolidColor(Color.Transparent),
+ backgroundFocused = normalBackground,
+ backgroundPressed = normalBackground,
+ backgroundHovered = normalBackground,
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("Button.default.disabledText"),
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ border = normalBorder,
+ borderDisabled = SolidColor(retrieveColorOrUnspecified("Button.default.disabledBorderColor")),
+ borderFocused = SolidColor(retrieveColorOrUnspecified("Button.default.focusedBorderColor")),
+ borderPressed = normalBorder,
+ borderHovered = normalBorder,
)
- val defaultBackgroundBrush = Brush.verticalGradient(retrieveColorsOrUnspecified("Button.default.startBackground", "Button.default.endBackground"))
- val defaultContentColor = retrieveColorOrUnspecified("Button.default.foreground")
- val defaultBorderStroke = Stroke(
- width = 1.dp,
- brush = Brush.verticalGradient(retrieveColorsOrUnspecified("Button.default.startBorderColor", "Button.default.endBorderColor")),
- alignment = Stroke.Alignment.Center
- )
- val defaultHaloStroke = Stroke(
- width = retrieveIntAsDp("Component.focusWidth"),
- color = retrieveColorOrUnspecified("Button.default.focusColor"),
- alignment = Stroke.Alignment.Outside
- )
-
- val transparentBrush = SolidColor(Color.Transparent)
- val disabledContentColor = retrieveColorOrUnspecified("Button.disabledText")
- val disabledBorderStroke = Stroke(
- width = 1.dp,
- brush = SolidColor(retrieveColorOrUnspecified("Button.disabledBorderColor")),
- alignment = Stroke.Alignment.Center
- )
-
- return ButtonDefaults(
- shape = RoundedCornerShape(retrieveIntAsDp("Button.arc") * 2), // Swing arcs are the diameter
- contentPadding = PaddingValues(horizontal = 16.dp),
- minWidth = 72.dp,
- minHeight = 24.dp, // From DarculaUIUtil#MINIMUM_HEIGHT
- outlinedButtonColors = buttonColors(
- backgroundBrush = backgroundBrush,
- contentColor = contentColor,
- borderStroke = borderStroke,
- disabledBackgroundBrush = transparentBrush,
- disabledContentColor = disabledContentColor,
- disabledBorderStroke = disabledBorderStroke,
- hoveredBackgroundBrush = backgroundBrush,
- hoveredContentColor = contentColor,
- hoveredBorderStroke = borderStroke,
- pressedBackgroundBrush = backgroundBrush,
- pressedContentColor = contentColor,
- pressedBorderStroke = borderStroke,
- focusedBackgroundBrush = backgroundBrush,
- focusedContentColor = contentColor,
- focusedBorderStroke = borderStroke,
- focusHaloStroke = haloStroke
- ),
- primaryButtonColors = buttonColors(
- backgroundBrush = defaultBackgroundBrush,
- contentColor = defaultContentColor,
- borderStroke = defaultBorderStroke,
- disabledBackgroundBrush = transparentBrush,
- disabledContentColor = disabledContentColor,
- disabledBorderStroke = disabledBorderStroke,
- hoveredBackgroundBrush = defaultBackgroundBrush,
- hoveredContentColor = defaultContentColor,
- hoveredBorderStroke = defaultBorderStroke,
- pressedBackgroundBrush = defaultBackgroundBrush,
- pressedContentColor = defaultContentColor,
- pressedBorderStroke = defaultBorderStroke,
- focusedBackgroundBrush = defaultBackgroundBrush,
- focusedContentColor = defaultContentColor,
- focusedBorderStroke = defaultBorderStroke,
- focusHaloStroke = defaultHaloStroke
+ return IntUiButtonStyle(
+ colors = colors,
+ metrics = IntUiButtonMetrics(
+ cornerSize = retrieveArcAsCornerSizeWithFallbacks("Button.default.arc", "Button.arc"),
+ padding = PaddingValues(horizontal = 14.dp), // see DarculaButtonUI.HORIZONTAL_PADDING
+ minSize = DpSize(DarculaUIUtil.MINIMUM_WIDTH.dp, DarculaUIUtil.MINIMUM_HEIGHT.dp),
+ borderWidth = DarculaUIUtil.LW.dp,
),
)
}
-private fun readCheckboxDefaults() = CheckboxDefaults(
- colors = checkBoxColors(
- checkmarkTintColor = Color.Unspecified, // There is no tint for the checkmark icon
- contentColor = retrieveColorOrUnspecified("Checkbox.foreground"),
- uncheckedBackground = retrieveColorOrUnspecified("Checkbox.background"),
- uncheckedStroke = ,
- uncheckedFocusedStroke =,
- uncheckedFocusHoloStroke =,
- uncheckedErrorHoloStroke =,
- uncheckedHoveredBackground = retrieveColorOrUnspecified("Checkbox.background"),
- uncheckedHoveredStroke =,
- uncheckedDisabledBackground = retrieveColorOrUnspecified("Checkbox.background"),
- uncheckedDisabledStroke =,
- checkedBackground = retrieveColorOrUnspecified("Checkbox.background"),
- checkedStroke =,
- checkedFocusedStroke =,
- checkedFocusHoloStroke =,
- checkedErrorHoloStroke =,
- checkedHoveredBackground = retrieveColorOrUnspecified("Checkbox.background"),
- checkedHoveredStroke =,
- checkedDisabledBackground = retrieveColorOrUnspecified("Checkbox.background"),
- checkedDisabledStroke =,
- disabledCheckmarkColor =,
- disabledTextColor =,
+private fun readOutlinedButtonStyle(): IntUiButtonStyle {
+ val normalBackground =
+ retrieveColorsOrUnspecified("Button.startBackground", "Button.endBackground")
+ .createVerticalBrush()
+ val normalContent = retrieveColorOrUnspecified("Button.foreground")
+ val normalBorder =
+ retrieveColorsOrUnspecified("Button.startBorderColor", "Button.endBorderColor")
+ .createVerticalBrush()
+
+ val colors = IntUiButtonColors(
+ background = normalBackground,
+ backgroundDisabled = SolidColor(Color.Transparent),
+ backgroundFocused = normalBackground,
+ backgroundPressed = normalBackground,
+ backgroundHovered = normalBackground,
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("Button.disabledText"),
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ border = normalBorder,
+ borderDisabled = SolidColor(retrieveColorOrUnspecified("Button.disabledBorderColor")),
+ borderFocused = SolidColor(retrieveColorOrUnspecified("Button.focusedBorderColor")),
+ borderPressed = normalBorder,
+ borderHovered = normalBorder,
+ )
+
+ return IntUiButtonStyle(
+ colors = colors,
+ metrics = IntUiButtonMetrics(
+ cornerSize = CornerSize(DarculaUIUtil.BUTTON_ARC.dp / 2),
+ padding = PaddingValues(horizontal = 14.dp), // see DarculaButtonUI.HORIZONTAL_PADDING
+ minSize = DpSize(DarculaUIUtil.MINIMUM_WIDTH.dp, DarculaUIUtil.MINIMUM_HEIGHT.dp),
+ borderWidth = DarculaUIUtil.LW.dp,
+ ),
+ )
+}
+
+private val iconsBasePath
+ get() = DirProvider().dir()
+
+private fun readCheckboxStyle(iconData: IntelliJThemeIconData, svgLoader: SvgLoader): IntUiCheckboxStyle {
+ val background = retrieveColorOrUnspecified("CheckBox.background")
+ val textColor = retrieveColorOrUnspecified("CheckBox.foreground")
+ val colors = IntUiCheckboxColors(
+ checkboxBackground = background,
+ checkboxBackgroundDisabled = background,
+ checkboxBackgroundSelected = background,
+ content = textColor,
+ contentDisabled = retrieveColorOrUnspecified("CheckBox.disabledText"),
+ contentSelected = textColor,
+ )
+
+ return IntUiCheckboxStyle(
+ colors = colors,
+ metrics = IntUiCheckboxMetrics(
+ checkboxSize = DarculaCheckBoxUI().defaultIcon.let { DpSize(it.iconWidth.dp, it.iconHeight.dp) },
+ checkboxCornerSize = CornerSize(3.dp), // See DarculaCheckBoxUI#drawCheckIcon
+ outlineWidth = 3.dp, // See DarculaCheckBoxUI#drawCheckIcon
+ iconContentGap = 5.dp, // See DarculaCheckBoxUI#textIconGap
+ ),
+ icons = IntUiCheckboxIcons(
+ checkbox = retrieveIcon(
+ baseIconPath = "${iconsBasePath}checkBox.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ prefixTokensProvider = { state: CheckboxState ->
+ if (state.toggleableState == ToggleableState.Indeterminate) "Indeterminate" else ""
+ },
+ ),
+ ),
+ )
+}
+
+// Note: there isn't a chip spec, nor a chip UI, so we're deriving this from the
+// styling defined in com.intellij.ide.ui.experimental.meetNewUi.MeetNewUiButton
+// To note:
+// 1. There is no real disabled state, we're making it sort of up
+// 2. Chips can be used as buttons (see run configs) or as radio buttons (see MeetNewUi)
+// 3. We also have a toggleable version because why not
+private fun readChipStyle(): IntUiChipStyle {
+ val normalBackground =
+ retrieveColorsOrUnspecified("Button.startBackground", "Button.endBackground")
+ .createVerticalBrush()
+ val normalContent = retrieveColorOrUnspecified("Label.foreground")
+ val normalBorder = retrieveColorOrUnspecified("Button.startBorderColor")
+ val disabledBorder = retrieveColorOrUnspecified("Button.disabledBorderColor")
+ val selectedBorder = retrieveColorOrUnspecified("Component.focusColor")
+
+ val colors = IntUiChipColors(
+ background = normalBackground,
+ backgroundDisabled = normalBackground,
+ backgroundFocused = normalBackground,
+ backgroundPressed = normalBackground,
+ backgroundHovered = normalBackground,
+ backgroundSelected = normalBackground,
+ backgroundSelectedDisabled = normalBackground,
+ backgroundSelectedPressed = normalBackground,
+ backgroundSelectedFocused = normalBackground,
+ backgroundSelectedHovered = normalBackground,
+ content = normalContent,
+ contentDisabled = normalContent,
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ contentSelected = normalContent,
+ contentSelectedDisabled = normalContent,
+ contentSelectedPressed = normalContent,
+ contentSelectedFocused = normalContent,
+ contentSelectedHovered = normalContent,
+ border = normalBorder,
+ borderDisabled = disabledBorder,
+ borderFocused = normalBorder,
+ borderPressed = normalBorder,
+ borderHovered = normalBorder,
+ borderSelected = selectedBorder,
+ borderSelectedDisabled = disabledBorder,
+ borderSelectedPressed = selectedBorder,
+ borderSelectedFocused = selectedBorder,
+ borderSelectedHovered = selectedBorder,
+ )
+ return IntUiChipStyle(
+ colors = colors,
+ metrics = IntUiChipMetrics(
+ cornerSize = CornerSize(6.dp),
+ padding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
+ borderWidth = 1.dp,
+ borderWidthSelected = 2.dp,
+ ),
+ )
+}
+
+private fun readDropdownStyle(
+ iconData: IntelliJThemeIconData,
+ svgLoader: SvgLoader,
+ menuStyle: IntUiMenuStyle,
+ dropdownTextStyle: TextStyle,
+): IntUiDropdownStyle {
+ val normalBackground = retrieveColorOrUnspecified("ComboBox.nonEditableBackground")
+ val normalContent = retrieveColorOrUnspecified("ComboBox.foreground")
+ val normalBorder = retrieveColorOrUnspecified("Component.borderColor")
+ val focusedBorder = retrieveColorOrUnspecified("Component.focusedBorderColor")
+
+ val colors = IntUiDropdownColors(
+ background = normalBackground,
+ backgroundDisabled = retrieveColorOrUnspecified("ComboBox.disabledBackground"),
+ backgroundFocused = normalBackground,
+ backgroundPressed = normalBackground,
+ backgroundHovered = normalBackground,
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("ComboBox.disabledForeground"),
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ border = normalBorder,
+ borderDisabled = retrieveColorOrUnspecified("Component.disabledBorderColor"),
+ borderFocused = focusedBorder,
+ borderPressed = focusedBorder,
+ borderHovered = normalBorder,
+ iconTint = Color.Unspecified,
+ iconTintDisabled = Color.Unspecified,
+ iconTintFocused = Color.Unspecified,
+ iconTintPressed = Color.Unspecified,
+ iconTintHovered = Color.Unspecified,
+ )
+
+ val arrowWidth = DarculaUIUtil.ARROW_BUTTON_WIDTH.dp
+ return IntUiDropdownStyle(
+ colors = colors,
+ metrics = IntUiDropdownMetrics(
+ arrowMinSize = DpSize(arrowWidth, DarculaUIUtil.MINIMUM_HEIGHT.dp),
+ minSize = DpSize(
+ DarculaUIUtil.MINIMUM_WIDTH.dp + arrowWidth,
+ DarculaUIUtil.MINIMUM_HEIGHT.dp,
+ ),
+ cornerSize = CornerSize(DarculaUIUtil.COMPONENT_ARC.dp),
+ contentPadding = retrieveInsetsAsPaddingValues("ComboBox.padding"),
+ borderWidth = DarculaUIUtil.BW.dp,
+ ),
+ icons = IntUiDropdownIcons(
+ chevronDown = retrieveIcon(
+ baseIconPath = "${iconsBasePath}general/chevron-down.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ ),
+ textStyle = dropdownTextStyle,
+ menuStyle = menuStyle,
+ )
+}
+
+private fun readGroupHeaderStyle() = IntUiGroupHeaderStyle(
+ colors = IntUiGroupHeaderColors(
+ content = retrieveColorOrUnspecified("Separator.foreground"),
+ divider = retrieveColorOrUnspecified("Separator.separatorColor"),
+ ),
+ metrics = IntUiGroupHeaderMetrics(
+ dividerThickness = 1.dp, // see DarculaSeparatorUI
+ indent = 1.dp, // see DarculaSeparatorUI
),
- shape = RoundedCornerShape(),
- width =,
- height =,
- contentSpacing =,
- textStyle =,
- checkMarkOn =,
- checkMarkOff =,
- checkMarkIndeterminate =,
)
+
+private fun readHorizontalProgressBarStyle() = IntUiHorizontalProgressBarStyle(
+ colors = IntUiHorizontalProgressBarColors(
+ track = retrieveColorOrUnspecified("ProgressBar.trackColor"),
+ progress = retrieveColorOrUnspecified("ProgressBar.progressColor"),
+ indeterminateBase = retrieveColorOrUnspecified("ProgressBar.indeterminateStartColor"),
+ indeterminateHighlight = retrieveColorOrUnspecified("ProgressBar.indeterminateEndColor"),
+ ),
+ metrics = IntUiHorizontalProgressBarMetrics(
+ cornerSize = CornerSize(100),
+ minHeight = 4.dp, // See DarculaProgressBarUI.DEFAULT_WIDTH
+ // See DarculaProgressBarUI.CYCLE_TIME_DEFAULT, DarculaProgressBarUI.REPAINT_INTERVAL_DEFAULT,
+ // and the "step" constant in DarculaProgressBarUI#paintIndeterminate
+ indeterminateHighlightWidth = (800 / 50 * 6).dp,
+ ),
+ indeterminateCycleDuration = 800.milliseconds, // See DarculaProgressBarUI.CYCLE_TIME_DEFAULT
+)
+
+private fun readLabelledTextFieldStyle(
+ inputFieldStyle: InputFieldStyle,
+ labelTextStyle: TextStyle,
+): IntUiLabelledTextFieldStyle {
+ val colors = IntUiLabelledTextFieldColors(
+ background = inputFieldStyle.colors.background,
+ backgroundDisabled = inputFieldStyle.colors.backgroundDisabled,
+ backgroundFocused = inputFieldStyle.colors.backgroundFocused,
+ backgroundPressed = inputFieldStyle.colors.backgroundPressed,
+ backgroundHovered = inputFieldStyle.colors.backgroundHovered,
+ content = inputFieldStyle.colors.content,
+ contentDisabled = inputFieldStyle.colors.contentDisabled,
+ contentFocused = inputFieldStyle.colors.contentFocused,
+ contentPressed = inputFieldStyle.colors.contentPressed,
+ contentHovered = inputFieldStyle.colors.contentHovered,
+ border = inputFieldStyle.colors.border,
+ borderDisabled = inputFieldStyle.colors.borderDisabled,
+ borderFocused = inputFieldStyle.colors.borderFocused,
+ borderPressed = inputFieldStyle.colors.borderPressed,
+ borderHovered = inputFieldStyle.colors.borderHovered,
+ caret = inputFieldStyle.colors.caret,
+ caretDisabled = inputFieldStyle.colors.caretDisabled,
+ caretFocused = inputFieldStyle.colors.caretFocused,
+ caretPressed = inputFieldStyle.colors.caretPressed,
+ caretHovered = inputFieldStyle.colors.caretHovered,
+ placeholder = retrieveColorOrUnspecified("Label.infoForeground"),
+ label = retrieveColorOrUnspecified("Label.foreground"),
+ hint = StatusText.DEFAULT_ATTRIBUTES.fgColor.toComposeColor(),
+ )
+
+ return IntUiLabelledTextFieldStyle(
+ colors = colors,
+ metrics = IntUiLabelledTextFieldMetrics(
+ cornerSize = inputFieldStyle.metrics.cornerSize,
+ contentPadding = inputFieldStyle.metrics.contentPadding,
+ minSize = inputFieldStyle.metrics.minSize,
+ borderWidth = inputFieldStyle.metrics.borderWidth,
+ labelSpacing = 6.dp,
+ hintSpacing = 6.dp,
+ ),
+ textStyle = inputFieldStyle.textStyle,
+ textStyles = IntUiLabelledTextFieldTextStyles(
+ label = labelTextStyle,
+ hint = labelTextStyle.copy(fontSize = labelTextStyle.fontSize - 1f),
+ ),
+ )
+}
+
+private fun readLinkStyle(
+ iconData: IntelliJThemeIconData,
+ svgLoader: SvgLoader,
+ linkTextStyle: TextStyle,
+): IntUiLinkStyle {
+ val normalContent =
+ retrieveColorOrUnspecified("Link.activeForeground").takeOrElse { retrieveColorOrUnspecified("Link.activeForeground") }
+
+ val colors = IntUiLinkColors(
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("Link.disabledForeground").takeOrElse {
+ retrieveColorOrUnspecified(
+ "Label.disabledForeground",
+ )
+ },
+ contentFocused = normalContent,
+ contentPressed = retrieveColorOrUnspecified("Link.pressedForeground").takeOrElse { retrieveColorOrUnspecified("link.pressed.foreground") },
+ contentHovered = retrieveColorOrUnspecified("Link.hoverForeground").takeOrElse { retrieveColorOrUnspecified("link.hover.foreground") },
+ contentVisited = retrieveColorOrUnspecified("Link.visitedForeground").takeOrElse { retrieveColorOrUnspecified("link.visited.foreground") },
+ )
+
+ return IntUiLinkStyle(
+ colors = colors,
+ metrics = IntUiLinkMetrics(
+ focusHaloCornerSize = CornerSize(Registry.intValue("ide.link.button.focus.round.arc", 4).dp),
+ textIconGap = 4.dp,
+ iconSize = DpSize.Unspecified,
+ ),
+ icons = IntUiLinkIcons(
+ dropdownChevron = retrieveIcon(
+ baseIconPath = "${iconsBasePath}general/chevron-down.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ externalLink = retrieveIcon(
+ baseIconPath = "${iconsBasePath}ide/external_link_arrow.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ ),
+ textStyles = IntUiLinkTextStyles(
+ normal = linkTextStyle,
+ disabled = linkTextStyle,
+ focused = linkTextStyle,
+ pressed = linkTextStyle,
+ hovered = linkTextStyle,
+ visited = linkTextStyle,
+ ),
+ )
+}
+
+private fun readMenuStyle(iconData: IntelliJThemeIconData, svgLoader: SvgLoader): IntUiMenuStyle {
+ val backgroundSelected = retrieveColorOrUnspecified("MenuItem.selectionBackground")
+ val foregroundSelected = retrieveColorOrUnspecified("MenuItem.selectionForeground")
+
+ val colors = IntUiMenuColors(
+ background = retrieveColorOrUnspecified("PopupMenu.background"),
+ border = retrieveColorOrUnspecified("Popup.borderColor").takeOrElse { retrieveColorOrUnspecified("Popup.Border.color") },
+ shadow = Color.Black.copy(alpha = .6f),
+ itemColors = IntUiMenuItemColors(
+ background = retrieveColorOrUnspecified("MenuItem.background"),
+ backgroundDisabled = retrieveColorOrUnspecified("MenuItem.disabledBackground"),
+ backgroundFocused = backgroundSelected,
+ backgroundPressed = backgroundSelected,
+ backgroundHovered = backgroundSelected,
+ content = retrieveColorOrUnspecified("PopupMenu.foreground"),
+ contentDisabled = retrieveColorOrUnspecified("PopupMenu.disabledForeground"),
+ contentFocused = foregroundSelected,
+ contentPressed = foregroundSelected,
+ contentHovered = foregroundSelected,
+ iconTint = Color.Unspecified,
+ iconTintDisabled = Color.Unspecified,
+ iconTintFocused = Color.Unspecified,
+ iconTintPressed = Color.Unspecified,
+ iconTintHovered = Color.Unspecified,
+ separator = retrieveColorOrUnspecified("Menu.separatorColor"),
+ ),
+ )
+
+ return IntUiMenuStyle(
+ colors = colors,
+ metrics = IntUiMenuMetrics(
+ cornerSize = CornerSize(IdeaPopupMenuUI.CORNER_RADIUS.dp),
+ menuMargin = PaddingValues(0.dp),
+ contentPadding = PaddingValues(horizontal = 8.dp, vertical = 12.dp),
+ offset = DpOffset(0.dp, 2.dp),
+ shadowSize = 12.dp,
+ borderWidth = retrieveIntAsDpOrUnspecified("Popup.borderWidth").takeOrElse { 1.dp },
+ itemMetrics = IntUiMenuItemMetrics(
+ selectionCornerSize = CornerSize(JBUI.CurrentTheme.PopupMenu.Selection.ARC.dp),
+ outerPadding = PaddingValues(horizontal = 6.dp),
+ contentPadding = PaddingValues(horizontal = 10.dp, vertical = 1.dp),
+ separatorPadding = PaddingValues(
+ horizontal = retrieveIntAsDpOrUnspecified("PopupMenuSeparator.withToEdge").takeOrElse { 0.dp },
+ vertical = retrieveIntAsDpOrUnspecified("PopupMenuSeparator.stripeIndent").takeOrElse { 0.dp },
+ ),
+ separatorThickness = retrieveIntAsDpOrUnspecified("PopupMenuSeparator.stripeWidth").takeOrElse { 0.dp },
+ ),
+ submenuMetrics = IntUiSubmenuMetrics(
+ offset = DpOffset(0.dp, (-8).dp),
+ ),
+ ),
+ icons = IntUiMenuIcons(
+ submenuChevron = retrieveIcon(
+ baseIconPath = "${iconsBasePath}general/chevron-down.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ ),
+ )
+}
+
+private fun readRadioButtonStyle(iconData: IntelliJThemeIconData, svgLoader: SvgLoader): IntUiRadioButtonStyle {
+ val normalContent = retrieveColorOrUnspecified("RadioButton.foreground")
+ val disabledContent = retrieveColorOrUnspecified("RadioButton.disabledText")
+ val colors = IntUiRadioButtonColors(
+ content = normalContent,
+ contentHovered = normalContent,
+ contentDisabled = disabledContent,
+ contentSelected = normalContent,
+ contentSelectedHovered = normalContent,
+ contentSelectedDisabled = disabledContent,
+ )
+
+ return IntUiRadioButtonStyle(
+ colors = colors,
+ metrics = IntUiRadioButtonMetrics(
+ radioButtonSize = DpSize(19.dp, 19.dp),
+ iconContentGap = retrieveIntAsDpOrUnspecified("RadioButton.textIconGap").takeOrElse { 4.dp },
+ ),
+ icons = IntUiRadioButtonIcons(
+ radioButton = retrieveIcon(
+ baseIconPath = "${iconsBasePath}darcula/radio.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ ),
+ )
+}
+
+private fun readScrollbarStyle(isDark: Boolean) = IntUiScrollbarStyle(
+ colors = IntUiScrollbarColors(
+ // See ScrollBarPainter.THUMB_BACKGROUND
+ thumbBackground = retrieveColorOrUnspecified("ScrollBar.Mac.Transparent.thumbColor")
+ .takeOrElse { if (isDark) Color(0x00000000) else Color(0x00808080) },
+ // See ScrollBarPainter.THUMB_HOVERED_BACKGROUND
+ thumbBackgroundHovered = retrieveColorOrUnspecified("ScrollBar.Mac.Transparent.hoverThumbColor")
+ .takeOrElse { if (isDark) Color(0x00000000) else Color(0x00808080) },
+ ),
+ metrics = IntUiScrollbarMetrics(
+ thumbCornerSize = CornerSize(100),
+ thumbThickness = 8.dp,
+ minThumbLength = 16.dp,
+ trackPadding = PaddingValues(start = 7.dp, end = 3.dp),
+ ),
+ hoverDuration = 300.milliseconds,
+)
+
+private fun readTextAreaStyle(textStyle: TextStyle, metrics: IntUiTextFieldMetrics): IntUiTextAreaStyle {
+ val normalBackground = retrieveColorOrUnspecified("TextArea.background")
+ val normalContent = retrieveColorOrUnspecified("TextArea.foreground")
+ val normalBorder = DarculaUIUtil.getOutlineColor(true, false).toComposeColor()
+ val focusedBorder = DarculaUIUtil.getOutlineColor(true, true).toComposeColor()
+ val normalCaret = retrieveColorOrUnspecified("TextArea.caretForeground")
+
+ val colors = IntUiTextAreaColors(
+ background = normalBackground,
+ backgroundDisabled = retrieveColorOrUnspecified("TextArea.disabledBackground"),
+ backgroundFocused = normalBackground,
+ backgroundPressed = normalBackground,
+ backgroundHovered = normalBackground,
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("TextArea.inactiveForeground"),
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ border = normalBorder,
+ borderDisabled = DarculaUIUtil.getOutlineColor(false, false).toComposeColor(),
+ borderFocused = focusedBorder,
+ borderPressed = focusedBorder,
+ borderHovered = normalBorder,
+ caret = normalCaret,
+ caretDisabled = normalCaret,
+ caretFocused = normalCaret,
+ caretPressed = normalCaret,
+ caretHovered = normalCaret,
+ placeholder = NamedColorUtil.getInactiveTextColor().toComposeColor(),
+ )
+
+ return IntUiTextAreaStyle(
+ colors = colors,
+ metrics = IntUiTextAreaMetrics(
+ cornerSize = metrics.cornerSize,
+ contentPadding = metrics.contentPadding,
+ minSize = metrics.minSize,
+ borderWidth = metrics.borderWidth,
+ ),
+ textStyle = textStyle,
+ )
+}
+
+private fun readTextFieldStyle(textFieldStyle: TextStyle): IntUiTextFieldStyle {
+ val normalBackground = retrieveColorOrUnspecified("TextField.background")
+ val normalContent = retrieveColorOrUnspecified("TextField.foreground")
+ val normalBorder = DarculaUIUtil.getOutlineColor(true, false).toComposeColor()
+ val focusedBorder = DarculaUIUtil.getOutlineColor(true, true).toComposeColor()
+ val normalCaret = retrieveColorOrUnspecified("TextField.caretForeground")
+
+ val colors = IntUiTextFieldColors(
+ background = normalBackground,
+ backgroundDisabled = retrieveColorOrUnspecified("TextField.disabledBackground"),
+ backgroundFocused = normalBackground,
+ backgroundPressed = normalBackground,
+ backgroundHovered = normalBackground,
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("TextField.inactiveForeground"),
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ border = normalBorder,
+ borderDisabled = DarculaUIUtil.getOutlineColor(false, false).toComposeColor(),
+ borderFocused = focusedBorder,
+ borderPressed = focusedBorder,
+ borderHovered = normalBorder,
+ caret = normalCaret,
+ caretDisabled = normalCaret,
+ caretFocused = normalCaret,
+ caretPressed = normalCaret,
+ caretHovered = normalCaret,
+ placeholder = NamedColorUtil.getInactiveTextColor().toComposeColor(),
+ )
+
+ return IntUiTextFieldStyle(
+ colors = colors,
+ metrics = IntUiTextFieldMetrics(
+ cornerSize = CornerSize(DarculaUIUtil.COMPONENT_ARC.dp),
+ contentPadding = PaddingValues(horizontal = 9.dp, vertical = 2.dp),
+ minSize = DpSize(DarculaUIUtil.MINIMUM_WIDTH.dp, DarculaUIUtil.MINIMUM_HEIGHT.dp),
+ borderWidth = DarculaUIUtil.LW.dp,
+ ),
+ textStyle = textFieldStyle,
+ )
+}
+
+private fun readLazyTreeStyle(iconData: IntelliJThemeIconData, svgLoader: SvgLoader): IntUiLazyTreeStyle {
+ val normalContent = retrieveColorOrUnspecified("Tree.foreground")
+ val selectedContent = retrieveColorOrUnspecified("Tree.selectionForeground")
+ val selectedElementBackground = retrieveColorOrUnspecified("Tree.selectionBackground")
+
+ val colors = IntUiLazyTreeColors(
+ content = normalContent,
+ contentFocused = normalContent,
+ contentSelected = selectedContent,
+ contentSelectedFocused = selectedContent,
+ elementBackgroundFocused = Color.Transparent,
+ elementBackgroundSelected = selectedElementBackground,
+ elementBackgroundSelectedFocused = selectedElementBackground,
+ )
+
+ return IntUiLazyTreeStyle(
+ colors = colors,
+ metrics = IntUiLazyTreeMetrics(
+ indentSize = retrieveIntAsDpOrUnspecified("Tree.leftChildIndent").takeOrElse { 7.dp } +
+ retrieveIntAsDpOrUnspecified("Tree.rightChildIndent").takeOrElse { 11.dp },
+ elementBackgroundCornerSize = CornerSize(JBUI.CurrentTheme.Tree.ARC.dp),
+ elementPadding = PaddingValues(horizontal = 12.dp),
+ elementContentPadding = PaddingValues(4.dp),
+ elementMinHeight = retrieveIntAsDpOrUnspecified("Tree.rowHeight").takeOrElse { 24.dp },
+ chevronContentGap = 2.dp, // See com.intellij.ui.tree.ui.ClassicPainter.GAP
+ ),
+ icons = IntUiLazyTreeIcons(
+ nodeChevronCollapsed = retrieveIcon(
+ baseIconPath = "${iconsBasePath}general/chevron-right.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ nodeChevronExpanded = retrieveIcon(
+ baseIconPath = "${iconsBasePath}general/chevron-down.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ ),
+ )
+}
+
+// See com.intellij.ui.tabs.impl.themes.DefaultTabTheme
+private fun readDefaultTabStyle(iconData: IntelliJThemeIconData, svgLoader: SvgLoader): IntUiTabStyle {
+ val normalBackground = JBUI.CurrentTheme.DefaultTabs.background().toComposeColor()
+ val selectedBackground = JBUI.CurrentTheme.DefaultTabs.underlinedTabBackground().toComposeColorOrUnspecified()
+ val normalContent = retrieveColorOrUnspecified("TabbedPane.foreground")
+ val selectedUnderline = retrieveColorOrUnspecified("TabbedPane.underlineColor")
+
+ val colors = IntUiTabColors(
+ background = normalBackground,
+ backgroundDisabled = normalBackground,
+ backgroundFocused = normalBackground,
+ backgroundPressed = selectedBackground,
+ backgroundHovered = JBUI.CurrentTheme.DefaultTabs.hoverBackground().toComposeColor(),
+ backgroundSelected = selectedBackground,
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("TabbedPane.disabledForeground"),
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ contentSelected = normalContent,
+ underline = Color.Transparent,
+ underlineDisabled = retrieveColorOrUnspecified("TabbedPane.disabledUnderlineColor"),
+ underlineFocused = Color.Transparent,
+ underlinePressed = selectedUnderline,
+ underlineHovered = Color.Transparent,
+ underlineSelected = selectedUnderline,
+ )
+
+ return IntUiTabStyle(
+ colors = colors,
+ metrics = IntUiTabMetrics(
+ underlineThickness = retrieveIntAsDpOrUnspecified("TabbedPane.tabSelectionHeight").takeOrElse { 2.dp },
+ tabPadding = retrieveInsetsAsPaddingValues("TabbedPane.tabInsets"),
+ closeContentGap = 4.dp,
+ tabHeight = retrieveIntAsDpOrUnspecified("TabbedPane.tabHeight").takeOrElse { 24.dp },
+ ),
+ icons = IntUiTabIcons(
+ close = retrieveIcon(
+ baseIconPath = "${iconsBasePath}expui/general/closeSmall.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ ),
+ contentAlpha = IntUiTabContentAlpha(
+ iconNormal = 1f,
+ iconDisabled = 1f,
+ iconFocused = 1f,
+ iconPressed = 1f,
+ iconHovered = 1f,
+ iconSelected = 1f,
+ labelNormal = 1f,
+ labelDisabled = 1f,
+ labelFocused = 1f,
+ labelPressed = 1f,
+ labelHovered = 1f,
+ labelSelected = 1f,
+ ),
+ )
+}
+
+private fun readEditorTabStyle(iconData: IntelliJThemeIconData, svgLoader: SvgLoader): IntUiTabStyle {
+ val normalBackground = JBUI.CurrentTheme.EditorTabs.background().toComposeColor()
+ val selectedBackground = JBUI.CurrentTheme.EditorTabs.underlinedTabBackground().toComposeColorOrUnspecified()
+ val normalContent = retrieveColorOrUnspecified("TabbedPane.foreground")
+ val selectedUnderline = retrieveColorOrUnspecified("TabbedPane.underlineColor")
+
+ val colors = IntUiTabColors(
+ background = normalBackground,
+ backgroundDisabled = normalBackground,
+ backgroundFocused = normalBackground,
+ backgroundPressed = selectedBackground,
+ backgroundHovered = JBUI.CurrentTheme.EditorTabs.hoverBackground().toComposeColor(),
+ backgroundSelected = selectedBackground,
+ content = normalContent,
+ contentDisabled = retrieveColorOrUnspecified("TabbedPane.disabledForeground"),
+ contentFocused = normalContent,
+ contentPressed = normalContent,
+ contentHovered = normalContent,
+ contentSelected = normalContent,
+ underline = Color.Transparent,
+ underlineDisabled = retrieveColorOrUnspecified("TabbedPane.disabledUnderlineColor"),
+ underlineFocused = Color.Transparent,
+ underlinePressed = selectedUnderline,
+ underlineHovered = Color.Transparent,
+ underlineSelected = selectedUnderline,
+ )
+
+ return IntUiTabStyle(
+ colors = colors,
+ metrics = IntUiTabMetrics(
+ underlineThickness = retrieveIntAsDpOrUnspecified("TabbedPane.tabSelectionHeight").takeOrElse { 2.dp },
+ tabPadding = retrieveInsetsAsPaddingValues("TabbedPane.tabInsets"),
+ closeContentGap = 4.dp,
+ tabHeight = retrieveIntAsDpOrUnspecified("TabbedPane.tabHeight").takeOrElse { 24.dp },
+ ),
+ icons = IntUiTabIcons(
+ close = retrieveIcon(
+ baseIconPath = "${iconsBasePath}expui/general/closeSmall.svg",
+ iconData = iconData,
+ svgLoader = svgLoader,
+ ),
+ ),
+ contentAlpha = IntUiTabContentAlpha(
+ iconNormal = .7f,
+ iconDisabled = .7f,
+ iconFocused = .7f,
+ iconPressed = 1f,
+ iconHovered = 1f,
+ iconSelected = 1f,
+ labelNormal = .7f,
+ labelDisabled = .7f,
+ labelFocused = .7f,
+ labelPressed = 1f,
+ labelHovered = 1f,
+ labelSelected = 1f,
+ ),
+ )
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntUiBridgeTheme.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntUiBridgeTheme.kt
deleted file mode 100644
index 77654b16c1da..000000000000
--- a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntUiBridgeTheme.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.jetbrains.jewel.bridge
-
-import androidx.compose.ui.text.TextStyle
-import org.jetbrains.jewel.ButtonDefaults
-import org.jetbrains.jewel.CheckboxDefaults
-import org.jetbrains.jewel.ChipDefaults
-import org.jetbrains.jewel.DropdownDefaults
-import org.jetbrains.jewel.GroupHeaderDefaults
-import org.jetbrains.jewel.IntelliJColors
-import org.jetbrains.jewel.LabelledTextFieldDefaults
-import org.jetbrains.jewel.LinkDefaults
-import org.jetbrains.jewel.MenuDefaults
-import org.jetbrains.jewel.ThemeColors
-import org.jetbrains.jewel.ProgressBarDefaults
-import org.jetbrains.jewel.RadioButtonDefaults
-import org.jetbrains.jewel.ScrollThumbDefaults
-import org.jetbrains.jewel.TextAreaDefaults
-import org.jetbrains.jewel.TextFieldDefaults
-import org.jetbrains.jewel.TreeDefaults
-import org.jetbrains.jewel.themes.intui.core.IntUiColorPalette
-import org.jetbrains.jewel.themes.intui.standalone.IntUiTheme
-
-class IntUiBridgeTheme internal constructor(
- override val isDark: Boolean,
- palette: IntUiColorPalette,
- override val colors: IntelliJColors,
- val themeColors: ThemeColors,
- override val buttonDefaults: ButtonDefaults,
- override val checkboxDefaults: CheckboxDefaults,
- override val groupHeaderDefaults: GroupHeaderDefaults,
- override val linkDefaults: LinkDefaults,
- override val textFieldDefaults: TextFieldDefaults,
- override val labelledTextFieldDefaults: LabelledTextFieldDefaults,
- override val textAreaDefaults: TextAreaDefaults,
- override val radioButtonDefaults: RadioButtonDefaults,
- override val dropdownDefaults: DropdownDefaults,
- override val contextMenuDefaults: MenuDefaults,
- override val defaultTextStyle: TextStyle,
- override val treeDefaults: TreeDefaults,
- override val chipDefaults: ChipDefaults,
- override val scrollThumbDefaults: ScrollThumbDefaults,
- override val progressBarDefaults: ProgressBarDefaults,
-): IntUiTheme(palette)
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntelliJResourcePainterProvider.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntelliJResourcePainterProvider.kt
new file mode 100644
index 000000000000..80b02cf88162
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/IntelliJResourcePainterProvider.kt
@@ -0,0 +1,59 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.ResourceLoader
+import com.intellij.ide.ui.IconMapLoader
+import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.thisLogger
+import org.jetbrains.jewel.InteractiveComponentState
+import org.jetbrains.jewel.JewelResourceLoader
+import org.jetbrains.jewel.SvgLoader
+import org.jetbrains.jewel.styling.ResourcePainterProvider
+
+class IntelliJResourcePainterProvider(
+ basePath: String,
+ svgLoader: SvgLoader,
+ prefixTokensProvider: (state: T) -> String = { "" },
+ suffixTokensProvider: (state: T) -> String = { "" },
+) : ResourcePainterProvider(basePath, svgLoader, prefixTokensProvider, suffixTokensProvider) {
+
+ private val logger = thisLogger()
+
+ private val mappingsByClassLoader
+ get() = service().loadIconMapping()
+
+ @Composable
+ override fun patchPath(state: T, basePath: String, resourceLoader: ResourceLoader): String {
+ val patchedPath = super.patchPath(state, basePath, resourceLoader)
+ return mapPath(patchedPath, resourceLoader)
+ }
+
+ private fun mapPath(originalPath: String, resourceLoader: ResourceLoader): String {
+ logger.debug("Loading SVG from '$originalPath'")
+ val searchClasses = (resourceLoader as? JewelResourceLoader)?.searchClasses
+ if (searchClasses == null) {
+ logger.warn(
+ "Tried loading a resource but the provided ResourceLoader is now a JewelResourceLoader; " +
+ "this is probably a bug. Make sure you always use JewelResourceLoaders.",
+ )
+ return originalPath
+ }
+
+ val allMappings = mappingsByClassLoader
+ if (allMappings.isEmpty()) {
+ logger.info("No mapping info available yet, can't check for '$originalPath' mapping.")
+ return originalPath
+ }
+
+ val applicableMappings = searchClasses.mapNotNull { allMappings[it.classLoader] }
+ val mappedPath = applicableMappings.firstNotNullOfOrNull { it[originalPath.removePrefix("/")] }
+
+ if (mappedPath == null) {
+ logger.debug("Icon '$originalPath' has no mapping defined.")
+ return originalPath
+ }
+
+ logger.debug("Icon '$originalPath' is mapped to '$mappedPath'.")
+ return mappedPath
+ }
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/JewelBridgeException.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/JewelBridgeException.kt
new file mode 100644
index 000000000000..2b5308e80193
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/JewelBridgeException.kt
@@ -0,0 +1,21 @@
+package org.jetbrains.jewel.bridge
+
+sealed class JewelBridgeException(override val message: String?) : RuntimeException(message) {
+
+ class KeyNotFoundException(key: String, type: String) : JewelBridgeException(
+ "Key '$key' not found in Swing LaF, was expecting a value of type $type",
+ )
+
+ class KeysNotFoundException(keys: List, type: String) : JewelBridgeException(
+ "Keys ${keys.joinToString(", ") { "'$it'" }} not found in Swing LaF, " +
+ "was expecting a value of type $type",
+ )
+}
+
+@Suppress("NOTHING_TO_INLINE") // Same implementation as error()
+internal inline fun keyNotFound(key: String, type: String): Nothing =
+ throw JewelBridgeException.KeyNotFoundException(key, type)
+
+@Suppress("NOTHING_TO_INLINE") // Same implementation as error()
+internal inline fun keysNotFound(keys: List, type: String): Nothing =
+ throw JewelBridgeException.KeysNotFoundException(keys, type)
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/ProjectLifecycle.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/ProjectLifecycle.kt
deleted file mode 100644
index 87588d3a1cd7..000000000000
--- a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/ProjectLifecycle.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.jetbrains.jewel.bridge
-
-import com.intellij.openapi.Disposable
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.cancel
-
-internal class ProjectLifecycle : Disposable, CoroutineScope {
-
- override val coroutineContext = SupervisorJob()
-
- override fun dispose() = cancel()
-}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/Svg.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/Svg.kt
deleted file mode 100644
index 03f906351d3b..000000000000
--- a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/Svg.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.jetbrains.jewel.bridge
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.res.loadSvgPainter
-import java.io.InputStream
-
-@Composable
-fun rememberSvgResource(resourcePath: String, classLoader: ClassLoader): Painter {
- val density = LocalDensity.current
- return remember(resourcePath, density) {
- useResource(resourcePath, classLoader) {
- loadSvgPainter(it, density)
- }
- }
-}
-
-inline fun useResource(
- resourcePath: String,
- classLoader: ClassLoader,
- block: (InputStream) -> T
-): T = openResource(resourcePath, classLoader).use(block)
-
-/**
- * Open [InputStream] from a resource stored in resources for the application.
- *
- * @throws IllegalArgumentException if there is no [resourcePath] in resources
- */
-@PublishedApi
-internal fun openResource(resourcePath: String, classLoader: ClassLoader): InputStream {
- return requireNotNull(classLoader.getResourceAsStream(resourcePath)) {
- "Resource $resourcePath not found"
- }
-}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingBridgeService.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingBridgeService.kt
new file mode 100644
index 000000000000..aeb2e0f988cc
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingBridgeService.kt
@@ -0,0 +1,92 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.ui.text.TextStyle
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.Service.Level
+import com.intellij.openapi.diagnostic.thisLogger
+import com.intellij.ui.NewUI
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import org.jetbrains.jewel.IntelliJComponentStyling
+import org.jetbrains.jewel.IntelliJSvgLoader
+import org.jetbrains.jewel.SvgLoader
+import org.jetbrains.jewel.themes.PaletteMapperFactory
+import org.jetbrains.jewel.themes.intui.core.IntUiThemeDefinition
+import org.jetbrains.jewel.themes.intui.core.IntelliJSvgPatcher
+
+@Service(Level.APP)
+class SwingBridgeService : Disposable {
+
+ private val logger = thisLogger()
+
+ // TODO use constructor injection when min IJ is 232+
+ private val coroutineScope: CoroutineScope =
+ CoroutineScope(SupervisorJob() + CoroutineName("JewelSwingBridge"))
+
+ // TODO we shouldn't assume it's Int UI, but we only have that for now
+ internal val currentBridgeThemeData: StateFlow =
+ IntelliJApplication.lookAndFeelChangedFlow(coroutineScope)
+ .map { readThemeData() }
+ .stateIn(coroutineScope, SharingStarted.Eagerly, BridgeThemeData.DEFAULT)
+
+ private suspend fun readThemeData(): BridgeThemeData {
+ val isIntUi = NewUI.isEnabled()
+ if (!isIntUi) {
+ // TODO return Darcula/IntelliJ Light theme instead
+ logger.warn("Darcula LaFs (aka \"old UI\") are not supported yet, falling back to Int UI")
+ }
+
+ val themeDefinition = createBridgeIntUiDefinition()
+ val svgLoader = createSvgLoader(themeDefinition)
+ return BridgeThemeData(
+ themeDefinition = createBridgeIntUiDefinition(),
+ svgLoader = svgLoader,
+ componentStyling = createSwingIntUiComponentStyling(themeDefinition, svgLoader),
+ )
+ }
+
+ override fun dispose() {
+ coroutineScope.cancel("Disposing Application...")
+ }
+
+ internal data class BridgeThemeData(
+ val themeDefinition: IntUiThemeDefinition,
+ val svgLoader: SvgLoader,
+ val componentStyling: IntelliJComponentStyling,
+ ) {
+
+ companion object {
+
+ val DEFAULT = run {
+ val themeDefinition = createBridgeIntUiDefinition(TextStyle.Default)
+ val svgLoader = createSvgLoader(themeDefinition)
+ BridgeThemeData(
+ themeDefinition = createBridgeIntUiDefinition(TextStyle.Default),
+ svgLoader = createSvgLoader(themeDefinition),
+ componentStyling = createSwingIntUiComponentStyling(
+ theme = themeDefinition,
+ svgLoader = svgLoader,
+ textAreaTextStyle = TextStyle.Default,
+ textFieldTextStyle = TextStyle.Default,
+ dropdownTextStyle = TextStyle.Default,
+ labelTextStyle = TextStyle.Default,
+ linkTextStyle = TextStyle.Default,
+ ),
+ )
+ }
+ }
+ }
+}
+
+private fun createSvgLoader(theme: IntUiThemeDefinition): SvgLoader {
+ val paletteMapper = PaletteMapperFactory.create(theme.isDark, theme.iconData, theme.colorPalette)
+ val svgPatcher = IntelliJSvgPatcher(paletteMapper)
+ return IntelliJSvgLoader(svgPatcher)
+}
diff --git a/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingBridgeTheme.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingBridgeTheme.kt
new file mode 100644
index 000000000000..c0b52d4fb925
--- /dev/null
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingBridgeTheme.kt
@@ -0,0 +1,19 @@
+package org.jetbrains.jewel.bridge
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import com.intellij.openapi.components.service
+import org.jetbrains.jewel.ExperimentalJewelApi
+import org.jetbrains.jewel.themes.intui.standalone.IntUiTheme
+
+private val bridgeService = service()
+
+@ExperimentalJewelApi
+@Composable
+fun SwingBridgeTheme(content: @Composable () -> Unit) {
+ val themeData by bridgeService.currentBridgeThemeData.collectAsState()
+
+ // TODO handle non-Int UI themes, too
+ IntUiTheme(themeData.themeDefinition, themeData.componentStyling, swingCompatMode = true, content)
+}
diff --git a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/SwingLafKey.kt b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingLafKey.kt
similarity index 75%
rename from platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/SwingLafKey.kt
rename to platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingLafKey.kt
index 0eae59304a73..03d3cc25cc93 100644
--- a/platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/SwingLafKey.kt
+++ b/platform/jewel/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/SwingLafKey.kt
@@ -1,11 +1,11 @@
-package org.jetbrains.jewel
+package org.jetbrains.jewel.bridge
@Retention(AnnotationRetention.SOURCE)
@Target(
AnnotationTarget.PROPERTY,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.VALUE_PARAMETER,
- AnnotationTarget.EXPRESSION
+ AnnotationTarget.EXPRESSION,
)
annotation class SwingLafKey(
val key: String,
diff --git a/platform/jewel/samples/ide-plugin/build.gradle.kts b/platform/jewel/samples/ide-plugin/build.gradle.kts
index 687fe4b55acf..1d94eafbd012 100644
--- a/platform/jewel/samples/ide-plugin/build.gradle.kts
+++ b/platform/jewel/samples/ide-plugin/build.gradle.kts
@@ -1,5 +1,3 @@
-import org.gradle.kotlin.dsl.projects
-
plugins {
jewel
alias(libs.plugins.composeDesktop)
@@ -7,15 +5,15 @@ plugins {
}
intellij {
- pluginName.set("Jewel")
- version.set("LATEST-EAP-SNAPSHOT")
+ pluginName.set("Jewel Demo")
plugins.set(listOf("org.jetbrains.kotlin"))
- version.set("2022.3")
+ version.set("2023.2.1")
}
// TODO remove this once the IJ Gradle plugin fixes their repositories bug
// See https://github.com/JetBrains/gradle-intellij-plugin/issues/776
repositories {
+ maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
maven("https://androidx.dev/storage/compose-compiler/repository/")
maven("https://www.jetbrains.com/intellij-repository/releases")
maven("https://cache-redirector.jetbrains.com/intellij-dependencies")
@@ -23,6 +21,7 @@ repositories {
}
dependencies {
- implementation(projects.themes.darcula.darculaIde)
- api(projects.foundation)
+ implementation(compose.desktop.currentOs)
+ implementation(projects.themes.intUi.intUiStandalone)
+ implementation(projects.ideLafBridge)
}
diff --git a/platform/jewel/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/JewelDemoToolWindow.kt b/platform/jewel/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/JewelDemoToolWindow.kt
index 36d65b7222ed..cf422b122154 100644
--- a/platform/jewel/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/JewelDemoToolWindow.kt
+++ b/platform/jewel/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/JewelDemoToolWindow.kt
@@ -2,184 +2,98 @@ package org.jetbrains.jewel.samples.ideplugin
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.selection.selectableGroup
-import androidx.compose.runtime.Composable
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.awt.SwingPanel
import androidx.compose.ui.unit.dp
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowFactory
-import com.intellij.util.ui.JBDimension
+import com.intellij.ui.JBColor
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import org.jetbrains.jewel.IntelliJTheme
-import org.jetbrains.jewel.Orientation
-import org.jetbrains.jewel.components.Button
-import org.jetbrains.jewel.components.Checkbox
-import org.jetbrains.jewel.components.CheckboxRow
-import org.jetbrains.jewel.components.Divider
-import org.jetbrains.jewel.components.RadioButtonRow
-import org.jetbrains.jewel.components.Tab
-import org.jetbrains.jewel.components.TabRow
-import org.jetbrains.jewel.components.TabScope
-import org.jetbrains.jewel.components.Text
-import org.jetbrains.jewel.components.TextField
-import org.jetbrains.jewel.components.rememberTabContainerState
-import org.jetbrains.jewel.themes.darcula.idebridge.IntelliJTheme
-import org.jetbrains.jewel.themes.darcula.idebridge.addComposePanel
-import javax.swing.JProgressBar
+import org.jetbrains.jewel.CheckboxRow
+import org.jetbrains.jewel.DefaultButton
+import org.jetbrains.jewel.ExperimentalJewelApi
+import org.jetbrains.jewel.LocalResourceLoader
+import org.jetbrains.jewel.OutlinedButton
+import org.jetbrains.jewel.Text
+import org.jetbrains.jewel.TextField
+import org.jetbrains.jewel.bridge.SwingBridgeTheme
+import org.jetbrains.jewel.bridge.addComposePanel
+import org.jetbrains.jewel.bridge.toComposeColor
+import org.jetbrains.jewel.themes.intui.standalone.IntUiTheme
@ExperimentalCoroutinesApi
internal class JewelDemoToolWindow : ToolWindowFactory, DumbAware {
- enum class RadioSample {
- Enabled, Disabled, Automatic, Unavailable
- }
-
+ @OptIn(ExperimentalJewelApi::class)
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
- toolWindow.addComposePanel("Compose Demo") {
- IntelliJTheme(this) {
- Box(
+ toolWindow.addComposePanel("Jewel") {
+ SwingBridgeTheme {
+ val resourceLoader = LocalResourceLoader.current
+ val bgColor by remember(IntUiTheme.isDark) { mutableStateOf(JBColor.PanelBackground.toComposeColor()) }
+
+ val scrollState = rememberScrollState()
+ Column(
modifier = Modifier
.fillMaxSize()
- .background(IntelliJTheme.palette.background),
- contentAlignment = Alignment.Center
+ .background(bgColor)
+ .verticalScroll(scrollState)
+ .padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp),
) {
- Column(verticalArrangement = Arrangement.spacedBy(16.dp, alignment = Alignment.CenterVertically)) {
- var clicks by remember { mutableStateOf(0) }
- Button({ clicks++ }) {
- Text("Hello world, $clicks")
+ Text("Here is a selection of our finest components:")
+
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ var clicks1 by remember { mutableStateOf(0) }
+ OutlinedButton({ clicks1++ }) {
+ Text("Outlined: $clicks1")
+ }
+ OutlinedButton({ }, enabled = false) {
+ Text("Outlined")
}
- var checked by remember { mutableStateOf(false) }
-
- var textFieldValue by remember { mutableStateOf("") }
- TextField(
- value = textFieldValue,
- onValueChange = {
- textFieldValue = it
- }
- )
-
- Row(
- modifier = Modifier.weight(1f),
- horizontalArrangement = Arrangement.spacedBy(24.dp)
- ) {
- Text("One")
- Divider(
- orientation = Orientation.Vertical,
- startIndent = 12.dp
- )
- Text("Two")
- Divider(orientation = Orientation.Vertical)
- Text("Three")
- Divider(orientation = Orientation.Vertical)
- Text("Four")
+ var clicks2 by remember { mutableStateOf(0) }
+ DefaultButton({ clicks2++ }) {
+ Text("Default: $clicks2")
}
-
- CheckboxRow(
- checked = checked,
- onCheckedChange = { checked = it }
- ) {
- Text("Hello, I am a themed checkbox")
- }
-
- val tabState = rememberTabContainerState("1")
- TabRow(tabState) {
- Section("1", "One")
- Section("2", "Two")
- Section("3", "Three")
- }
- Column(modifier = Modifier.fillMaxSize()) {
- when (tabState.selectedKey) {
- "1" -> Text("Content of One")
- "2" -> Text("Content of Two")
- "3" -> Text("Content of Three")
- }
- }
-
- var radioState by remember { mutableStateOf(RadioSample.Automatic) }
- Column(
- Modifier.selectableGroup(),
- verticalArrangement = Arrangement.spacedBy(IntelliJTheme.metrics.singlePadding)
- ) {
- RadioButtonRow(
- selected = radioState == RadioSample.Automatic,
- onClick = { radioState = RadioSample.Automatic }
- ) {
- Text("Automatic detection of the property", Modifier.alignByBaseline())
- }
- RadioButtonRow(
- selected = radioState == RadioSample.Enabled,
- onClick = { radioState = RadioSample.Enabled }
- ) {
- Text("Enable the property", Modifier.alignByBaseline())
- }
- RadioButtonRow(
- selected = radioState == RadioSample.Disabled,
- onClick = { radioState = RadioSample.Disabled }
- ) {
- Text("Disable the property", Modifier.alignByBaseline())
- }
- RadioButtonRow(
- selected = radioState == RadioSample.Unavailable,
- onClick = { radioState = RadioSample.Unavailable },
- enabled = false
- ) {
- Text("Unavailable", Modifier.alignByBaseline())
- }
+ DefaultButton({ }, enabled = false) {
+ Text("Default")
}
}
- }
- }
- }
- toolWindow.addComposePanel("Compose Demo 2") {
- IntelliJTheme(this) {
- Box(
- modifier = Modifier.fillMaxWidth(),
- contentAlignment = Alignment.Center
- ) {
- var checked by remember { mutableStateOf(true) }
- Column {
- Button({}) {
- Text("Hello world 2")
- }
- Checkbox(
- checked = checked,
- onCheckedChange = { checked = it }
- )
- IndeterminateProgressBar(
- modifier = Modifier.width(100.dp)
- )
+ var textFieldValue by remember { mutableStateOf("") }
+ TextField(
+ value = textFieldValue,
+ onValueChange = { textFieldValue = it },
+ placeholder = { Text("Write something...") },
+ modifier = Modifier.width(200.dp),
+ )
- SwingPanel(factory = {
- JProgressBar().apply {
- isIndeterminate = true
- preferredSize = JBDimension(100, 4)
- }
- })
+ var checked by remember { mutableStateOf(false) }
+ CheckboxRow(
+ checked = checked,
+ onCheckedChange = { checked = it },
+ resourceLoader = resourceLoader,
+ ) {
+ Text("Hello, I am a themed checkbox")
}
}
}
}
}
}
-
-@Composable
-private fun TabScope.Section(key: String, caption: String) {
- Tab(key) {
- Text(caption)
- }
-}
diff --git a/platform/jewel/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/PKGSDemo.kt b/platform/jewel/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/PKGSDemo.kt
deleted file mode 100644
index b1865405b5f3..000000000000
--- a/platform/jewel/samples/ide-plugin/src/main/kotlin/org/jetbrains/jewel/samples/ideplugin/PKGSDemo.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.jetbrains.jewel.samples.ideplugin
-
-import androidx.compose.foundation.VerticalScrollbar
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.rememberScrollbarAdapter
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.wm.ToolWindow
-import com.intellij.openapi.wm.ToolWindowFactory
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import org.jetbrains.jewel.components.Surface
-import org.jetbrains.jewel.components.Text
-import org.jetbrains.jewel.foundation.tree.Tree
-import org.jetbrains.jewel.foundation.tree.TreeView
-import org.jetbrains.jewel.foundation.tree.asTree
-import org.jetbrains.jewel.themes.darcula.idebridge.IntelliJTheme
-import org.jetbrains.jewel.themes.darcula.idebridge.addComposePanel
-import java.nio.file.Paths
-
-@ExperimentalCoroutinesApi
-internal class PKGSDemo : ToolWindowFactory, DumbAware {
-
- override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
- toolWindow.addComposePanel("Packages") {
- IntelliJTheme {
- Surface {
- val tree by remember { mutableStateOf(Paths.get(project.basePath ?: System.getProperty("user.dir")).asTree()) }
- Box {
- val listState = rememberLazyListState()
- TreeView(
- modifier = Modifier.fillMaxWidth(),
- tree = tree,
- onElementClick = { println("clicked ${it.data.absolutePath}") },
- onElementDoubleClick = { println("doubleClicked ${it.data.absolutePath}") },
- arrowContent = { isOpen ->
- Box(Modifier.padding(2.dp)) {
- Text("[${if (isOpen) "x" else " "}]")
- }
- },
- selectionBackgroundColor = org.jetbrains.jewel.IntelliJTheme.palette.controlStrokeFocused,
- selectionFocusedBackgroundColor = org.jetbrains.jewel.IntelliJTheme.palette.controlStrokeFocused
-
- ) {
- val text: String = when (it) {
- is Tree.Element.Leaf<*> -> it.data.name
- is Tree.Element.Node<*> -> "[${it.data.name}]"
- }
- Text(modifier = Modifier.fillMaxWidth(), text = text, softWrap = false)
- }
- if (listState.layoutInfo.totalItemsCount > listState.layoutInfo.visibleItemsInfo.size) {
- VerticalScrollbar(
- modifier = Modifier.align(Alignment.CenterEnd).padding(horizontal = 2.dp),
- adapter = rememberScrollbarAdapter(listState)
- )
- }
- }
- }
- }
- }
- }
-}
diff --git a/platform/jewel/samples/ide-plugin/src/main/resources/META-INF/plugin.xml b/platform/jewel/samples/ide-plugin/src/main/resources/META-INF/plugin.xml
new file mode 100644
index 000000000000..e23ed6944d07
--- /dev/null
+++ b/platform/jewel/samples/ide-plugin/src/main/resources/META-INF/plugin.xml
@@ -0,0 +1,19 @@
+
+ org.jetbrains.jewel.demo
+ Jewel Demo
+ JetBrains
+
+ Jewel repository for more information.
+ ]]>
+
+ com.intellij.modules.platform
+
+
+
+
+
+
diff --git a/platform/jewel/samples/ide-plugin/src/main/resources/META-INF/pluginIcon.svg b/platform/jewel/samples/ide-plugin/src/main/resources/META-INF/pluginIcon.svg
new file mode 100644
index 000000000000..d26083978a4e
--- /dev/null
+++ b/platform/jewel/samples/ide-plugin/src/main/resources/META-INF/pluginIcon.svg
@@ -0,0 +1,7 @@
+
diff --git a/platform/jewel/samples/ide-plugin/src/resources/META-INF/plugin.xml b/platform/jewel/samples/ide-plugin/src/resources/META-INF/plugin.xml
deleted file mode 100644
index 261584c03bd2..000000000000
--- a/platform/jewel/samples/ide-plugin/src/resources/META-INF/plugin.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
- org.jetbrains.compose.desktop.ide.theme
- Jewel
- JetBrains
-
-
-
-
-
-
-
-
-
diff --git a/platform/jewel/samples/standalone/build.gradle.kts b/platform/jewel/samples/standalone/build.gradle.kts
index 220c739a676d..d85aa0ea463c 100644
--- a/platform/jewel/samples/standalone/build.gradle.kts
+++ b/platform/jewel/samples/standalone/build.gradle.kts
@@ -9,8 +9,6 @@ plugins {
dependencies {
implementation(projects.themes.intUi.intUiStandalone)
- implementation(libs.compose.components.splitpane)
- implementation(projects.foundation)
}
compose.desktop {
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/Main.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/Main.kt
index 15ffb6b9fb8a..ec41aed913e6 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/Main.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/Main.kt
@@ -49,7 +49,7 @@ fun main() {
val icon = svgResource("icons/jewel-logo.svg")
singleWindowApplication(
title = "Jewel component catalog",
- icon = icon
+ icon = icon,
) {
var isDark by remember { mutableStateOf(false) }
var swingCompat by remember { mutableStateOf(false) }
@@ -68,7 +68,7 @@ fun main() {
Row(
modifier = Modifier.fillMaxWidth().padding(8.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
CheckboxRow("Dark", isDark, resourceLoader, { isDark = it })
CheckboxRow("Swing compat", swingCompat, resourceLoader, { swingCompat = it })
@@ -91,8 +91,8 @@ private fun ComponentShowcase() {
Modifier.width(IntrinsicSize.Max)
.verticalScroll(verticalScrollState)
.padding(24.dp),
- verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterVertically),
- horizontalAlignment = Alignment.CenterHorizontally
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ horizontalAlignment = Alignment.Start,
) {
Borders()
Buttons()
@@ -100,16 +100,16 @@ private fun ComponentShowcase() {
Checkboxes()
RadioButtons()
Links()
+ TextFields()
TextAreas()
ProgressBar()
- TextFields()
- Tabs()
ChipsAndTree()
+ Tabs()
}
VerticalScrollbar(
modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
- adapter = rememberScrollbarAdapter(verticalScrollState)
+ adapter = rememberScrollbarAdapter(verticalScrollState),
)
}
}
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Borders.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Borders.kt
index a40a8749ece4..cc7b0be4cbb7 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Borders.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Borders.kt
@@ -32,32 +32,32 @@ internal fun Borders() {
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
RadioButtonRow(
text = "Inside",
selected = borderAlignment == Stroke.Alignment.Inside,
resourceLoader = resourceLoader,
- onClick = { borderAlignment = Stroke.Alignment.Inside }
+ onClick = { borderAlignment = Stroke.Alignment.Inside },
)
RadioButtonRow(
text = "Center",
selected = borderAlignment == Stroke.Alignment.Center,
resourceLoader = resourceLoader,
- onClick = { borderAlignment = Stroke.Alignment.Center }
+ onClick = { borderAlignment = Stroke.Alignment.Center },
)
RadioButtonRow(
text = "Outside",
selected = borderAlignment == Stroke.Alignment.Outside,
resourceLoader = resourceLoader,
- onClick = { borderAlignment = Stroke.Alignment.Outside }
+ onClick = { borderAlignment = Stroke.Alignment.Outside },
)
}
var width by remember { mutableStateOf(1.dp) }
var expand by remember { mutableStateOf(0.dp) }
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
OutlinedButton({
width += 1.dp
@@ -82,7 +82,7 @@ internal fun Borders() {
}
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
Box(
Modifier.size(28.dp, 28.dp)
@@ -91,8 +91,8 @@ internal fun Borders() {
width,
IntUiTheme.colorPalette.blue(4),
CircleShape,
- expand
- )
+ expand,
+ ),
)
Box(
Modifier.size(72.dp, 28.dp)
@@ -101,8 +101,8 @@ internal fun Borders() {
width,
IntUiTheme.colorPalette.blue(4),
RectangleShape,
- expand
- )
+ expand,
+ ),
)
Box(
Modifier.size(72.dp, 28.dp)
@@ -111,8 +111,8 @@ internal fun Borders() {
width,
IntUiTheme.colorPalette.blue(4),
RoundedCornerShape(4.dp),
- expand
- )
+ expand,
+ ),
)
Box(
Modifier.size(72.dp, 28.dp)
@@ -121,8 +121,8 @@ internal fun Borders() {
width,
IntUiTheme.colorPalette.blue(4),
RoundedCornerShape(4.dp, 0.dp, 4.dp, 0.dp),
- expand
- )
+ expand,
+ ),
)
}
}
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Buttons.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Buttons.kt
index a6eded6a3a3e..3096ed8849e2 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Buttons.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Buttons.kt
@@ -1,12 +1,11 @@
package org.jetbrains.jewel.samples.standalone.components
-import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.DefaultButton
import org.jetbrains.jewel.GroupHeader
@@ -14,31 +13,27 @@ import org.jetbrains.jewel.OutlinedButton
import org.jetbrains.jewel.Text
@Composable
-fun ColumnScope.Buttons() {
+fun Buttons() {
GroupHeader("Buttons")
Row(
- horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
+ verticalAlignment = Alignment.CenterVertically,
) {
- OutlinedButton({
- }) {
- Text("Cancel")
+ OutlinedButton(onClick = { }) {
+ Text("Outlined")
}
- OutlinedButton({
- }) {
- Text("Apply")
+
+ OutlinedButton(onClick = {}, enabled = false) {
+ Text("Outlined Disabled")
}
- OutlinedButton({}, enabled = false) {
- Text("Disabled")
+
+ DefaultButton(onClick = {}) {
+ Text("Default")
}
- DefaultButton(
- {
- },
- interactionSource = remember {
- MutableInteractionSource()
- }
- ) {
- Text("OK")
+
+ DefaultButton(onClick = {}, enabled = false) {
+ Text("Default disabled")
}
}
}
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Checkboxes.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Checkboxes.kt
index ce6baefb452d..8784645346ce 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Checkboxes.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Checkboxes.kt
@@ -20,7 +20,7 @@ fun Checkboxes() {
GroupHeader("Checkboxes")
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
val resourceLoader = LocalResourceLoader.current
var checked by remember { mutableStateOf(ToggleableState.On) }
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ChipsAndTree.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ChipsAndTree.kt
index 193504ecf01c..bd6a1d426a57 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ChipsAndTree.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ChipsAndTree.kt
@@ -9,14 +9,19 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.Chip
import org.jetbrains.jewel.GroupHeader
import org.jetbrains.jewel.LazyTree
import org.jetbrains.jewel.LocalResourceLoader
+import org.jetbrains.jewel.RadioButtonChip
import org.jetbrains.jewel.Text
+import org.jetbrains.jewel.ToggleableChip
import org.jetbrains.jewel.foundation.tree.buildTree
@Composable
@@ -35,16 +40,55 @@ fun ChipsAndTree() {
@Composable
fun ChipsRow(modifier: Modifier = Modifier) {
- Row(modifier) {
+ Row(modifier, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
+ var selectedIndex by remember { mutableStateOf(-1) }
+ RadioButtonChip(
+ selected = selectedIndex == 0,
+ onClick = { selectedIndex = 0 },
+ enabled = true,
+ ) {
+ Text("First")
+ }
+
+ RadioButtonChip(
+ selected = selectedIndex == 1,
+ onClick = { selectedIndex = 1 },
+ enabled = true,
+ ) {
+ Text("Second")
+ }
+
+ RadioButtonChip(
+ selected = selectedIndex == 2,
+ onClick = { selectedIndex = 2 },
+ enabled = true,
+ ) {
+ Text("Third")
+ }
+ }
+ Row(modifier, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
+ var isChecked by remember { mutableStateOf(false) }
+ ToggleableChip(
+ checked = isChecked,
+ onClick = {
+ isChecked = it
+ },
+ enabled = true,
+ ) {
+ Text("Toggleable")
+ }
+
+ var count by remember { mutableStateOf(1) }
Chip(
enabled = true,
- onChipClick = {}
+ onClick = { count++ },
) {
- Text("Enabled")
+ Text("Clicks: $count")
}
+
Chip(
enabled = false,
- onChipClick = {}
+ onClick = {},
) {
Text("Disabled")
}
@@ -79,7 +123,7 @@ fun TreeSample(modifier: Modifier = Modifier) {
onElementClick = {},
onElementDoubleClick = {},
tree = tree,
- resourceLoader = resourceLoader
+ resourceLoader = resourceLoader,
) { element ->
Box(Modifier.fillMaxWidth()) {
Text(element.data, modifier.padding(2.dp))
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Dropdowns.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Dropdowns.kt
index 4bfdb8a0f89f..98cbd5562983 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Dropdowns.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Dropdowns.kt
@@ -14,14 +14,14 @@ import org.jetbrains.jewel.GroupHeader
import org.jetbrains.jewel.LocalResourceLoader
import org.jetbrains.jewel.Outline
import org.jetbrains.jewel.Text
-import org.jetbrains.jewel.divider
+import org.jetbrains.jewel.separator
@Composable
fun Dropdowns() {
GroupHeader("Dropdowns")
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
val items = remember {
listOf(
@@ -30,7 +30,7 @@ fun Dropdowns() {
"---",
"High Contrast",
"Darcula",
- "IntelliJ Light"
+ "IntelliJ Light",
)
}
var selected by remember { mutableStateOf(items.first()) }
@@ -40,7 +40,7 @@ fun Dropdowns() {
enabled = false,
resourceLoader = resourceLoader,
menuContent = {
- }
+ },
) {
Text(selected)
}
@@ -49,7 +49,7 @@ fun Dropdowns() {
menuContent = {
items.forEach {
if (it == "---") {
- divider()
+ separator()
} else {
selectableItem(selected == it, {
selected = it
@@ -58,11 +58,11 @@ fun Dropdowns() {
}
}
}
- divider()
+ separator()
submenu(submenu = {
items.forEach {
if (it == "---") {
- divider()
+ separator()
} else {
selectableItem(selected == it, {
selected = it
@@ -71,11 +71,11 @@ fun Dropdowns() {
}
}
}
- divider()
+ separator()
submenu(submenu = {
items.forEach {
if (it == "---") {
- divider()
+ separator()
} else {
selectableItem(selected == it, {
selected = it
@@ -90,7 +90,7 @@ fun Dropdowns() {
}) {
Text("Submenu")
}
- }
+ },
) {
Text(selected)
}
@@ -100,7 +100,7 @@ fun Dropdowns() {
menuContent = {
items.forEach {
if (it == "---") {
- divider()
+ separator()
} else {
selectableItem(selected == it, {
selected = it
@@ -109,7 +109,7 @@ fun Dropdowns() {
}
}
}
- }
+ },
) {
Text(selected)
}
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Links.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Links.kt
index a3bc05081cae..c75d39f34031 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Links.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Links.kt
@@ -15,7 +15,7 @@ import org.jetbrains.jewel.GroupHeader
import org.jetbrains.jewel.Link
import org.jetbrains.jewel.LocalResourceLoader
import org.jetbrains.jewel.Text
-import org.jetbrains.jewel.divider
+import org.jetbrains.jewel.separator
@Composable
fun Links() {
@@ -24,7 +24,7 @@ fun Links() {
val resourceLoader = LocalResourceLoader.current
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
Link("Link", resourceLoader, {})
@@ -37,14 +37,14 @@ fun Links() {
"---",
"High Contrast",
"Darcula",
- "IntelliJ Light"
+ "IntelliJ Light",
)
}
var selected by remember { mutableStateOf(items.first()) }
DropdownLink("DropdownLink", resourceLoader) {
items.forEach {
if (it == "---") {
- divider()
+ separator()
} else {
selectableItem(selected == it, {
selected = it
@@ -57,7 +57,7 @@ fun Links() {
}
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
Link("Link", resourceLoader, {}, enabled = false)
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ProgressBar.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ProgressBar.kt
index cbb62ee114c6..ae8d6d7787e8 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ProgressBar.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/ProgressBar.kt
@@ -17,12 +17,14 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
+import org.jetbrains.jewel.GroupHeader
import org.jetbrains.jewel.HorizontalProgressBar
import org.jetbrains.jewel.IndeterminateHorizontalProgressBar
import org.jetbrains.jewel.Text
@Composable
fun ProgressBar() {
+ GroupHeader("Progress bars")
val transition = rememberInfiniteTransition()
val currentOffset by transition.animateFloat(
initialValue = 0f,
@@ -32,8 +34,8 @@ fun ProgressBar() {
durationMillis = 4000
0f at 1000
1f at 3000
- }
- )
+ },
+ ),
)
var intermittentProgress by remember { mutableStateOf(0f) }
LaunchedEffect(Unit) {
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/RadioButtons.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/RadioButtons.kt
index 6ff26f6362be..a2bc7569626f 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/RadioButtons.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/RadioButtons.kt
@@ -19,7 +19,7 @@ fun RadioButtons() {
GroupHeader("RadioButtons")
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
val resourceLoader = LocalResourceLoader.current
var index by remember { mutableStateOf(0) }
@@ -27,7 +27,7 @@ fun RadioButtons() {
text = "Default",
selected = index == 0,
onClick = { index = 0 },
- resourceLoader = resourceLoader
+ resourceLoader = resourceLoader,
)
RadioButtonRow(
@@ -35,7 +35,7 @@ fun RadioButtons() {
selected = index == 1,
onClick = { index = 1 },
outline = Outline.Error,
- resourceLoader = resourceLoader
+ resourceLoader = resourceLoader,
)
RadioButtonRow(
@@ -43,7 +43,7 @@ fun RadioButtons() {
selected = index == 2,
onClick = { index = 2 },
outline = Outline.Warning,
- resourceLoader = resourceLoader
+ resourceLoader = resourceLoader,
)
RadioButtonRow(
@@ -51,7 +51,7 @@ fun RadioButtons() {
selected = index == 3,
onClick = { index = 3 },
enabled = false,
- resourceLoader = resourceLoader
+ resourceLoader = resourceLoader,
)
}
}
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Tabs.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Tabs.kt
index 1fc538534f11..1e4612b6022f 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Tabs.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/Tabs.kt
@@ -57,7 +57,7 @@ private fun DefaultTabShowcase() {
.coerceIn(0..maxPossibleIndex)
}
},
- onClick = { selectedTabIndex = index }
+ onClick = { selectedTabIndex = index },
)
}
}
@@ -92,7 +92,7 @@ private fun EditorTabShowcase() {
.coerceIn(0..maxPossibleIndex)
}
},
- onClick = { selectedTabIndex = index }
+ onClick = { selectedTabIndex = index },
)
}
}
@@ -119,7 +119,7 @@ private fun TabStripWithAddButton(
IconButton(
onClick = onAddClick,
- modifier = Modifier.size(IntelliJTheme.defaultTabStyle.metrics.tabHeight)
+ modifier = Modifier.size(IntelliJTheme.defaultTabStyle.metrics.tabHeight),
) {
Icon("icons/intui/add.svg", contentDescription = "Add a tab")
}
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextAreas.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextAreas.kt
index d8e70253abdf..f85ca02e39df 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextAreas.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextAreas.kt
@@ -2,7 +2,6 @@ package org.jetbrains.jewel.samples.standalone.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
@@ -14,43 +13,53 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.GroupHeader
+import org.jetbrains.jewel.Outline
import org.jetbrains.jewel.Text
import org.jetbrains.jewel.TextArea
+@Suppress("SpellCheckingInspection")
+private const val LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. \n" +
+ "Sed auctor, neque in accumsan vehicula, enim purus vestibulum odio, non tristique dolor quam vel ipsum. \n" +
+ "Proin egestas, orci id hendrerit bibendum, nisl neque imperdiet nisl, a euismod nibh diam nec lectus. \n" +
+ "Duis euismod, quam nec aliquam iaculis, dolor lorem bibendum turpis, vel malesuada augue sapien vel mi. \n" +
+ "Quisque ut facilisis nibh. Maecenas euismod hendrerit sem, ac scelerisque odio auctor nec. \n" +
+ "Sed sit amet consequat eros. Donec nisl tellus, accumsan nec ligula in, eleifend sodales sem. \n" +
+ "Sed malesuada, nulla ac eleifend fermentum, nibh mi consequat quam, quis convallis lacus nunc eu dui. \n" +
+ "Pellentesque eget enim quis orci porttitor consequat sed sed quam. \n" +
+ "Sed aliquam, nisl et lacinia lacinia, diam nunc laoreet nisi, sit amet consectetur dolor lorem et sem. \n" +
+ "Duis ultricies, mauris in aliquam interdum, orci nulla finibus massa, a tristique urna sapien vel quam. \n" +
+ "Sed nec sapien nec dui rhoncus bibendum. Sed blandit bibendum libero."
+
@Composable
fun TextAreas() {
GroupHeader("TextAreas")
Row(
- Modifier.height(144.dp).padding(horizontal = 16.dp),
- horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ Modifier.padding(horizontal = 16.dp).height(150.dp),
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
+ verticalAlignment = Alignment.Top,
) {
- var text1 by remember {
- mutableStateOf(
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. \n" +
- "Sed auctor, neque in accumsan vehicula, enim purus vestibulum odio, non tristique dolor quam vel ipsum. \n" +
- "Proin egestas, orci id hendrerit bibendum, nisl neque imperdiet nisl, a euismod nibh diam nec lectus. \n" +
- "Duis euismod, quam nec aliquam iaculis, dolor lorem bibendum turpis, vel malesuada augue sapien vel mi. \n" +
- "Quisque ut facilisis nibh. Maecenas euismod hendrerit sem, ac scelerisque odio auctor nec. \n" +
- "Sed sit amet consequat eros. Donec nisl tellus, accumsan nec ligula in, eleifend sodales sem. \n" +
- "Sed malesuada, nulla ac eleifend fermentum, nibh mi consequat quam, quis convallis lacus nunc eu dui. \n" +
- "Pellentesque eget enim quis orci porttitor consequat sed sed quam. \n" +
- "Sed aliquam, nisl et lacinia lacinia, diam nunc laoreet nisi, sit amet consectetur dolor lorem et sem. \n" +
- "Duis ultricies, mauris in aliquam interdum, orci nulla finibus massa, a tristique urna sapien vel quam. \n" +
- "Sed nec sapien nec dui rhoncus bibendum. Sed blandit bibendum libero."
- )
- }
- TextArea(text1, { text1 = it }, modifier = Modifier.weight(1f).fillMaxHeight())
+ var text1 by remember { mutableStateOf(LOREM_IPSUM) }
+ TextArea(text1, { text1 = it }, modifier = Modifier.weight(1f))
- TextArea(text1, { text1 = it }, modifier = Modifier.weight(1f).fillMaxHeight(), isError = true)
+ var text2 by remember { mutableStateOf(LOREM_IPSUM) }
+ TextArea(text2, { text2 = it }, modifier = Modifier.weight(1f), enabled = false)
- TextArea(text1, { text1 = it }, modifier = Modifier.weight(1f).fillMaxHeight(), enabled = false)
+ var text3 by remember { mutableStateOf("") }
+ TextArea(
+ text3,
+ { text3 = it },
+ modifier = Modifier.weight(1f),
+ outline = Outline.Error,
+ placeholder = { Text("Text area with error") },
+ )
var text4 by remember { mutableStateOf("") }
- TextArea(text4, { text4 = it }, hint = {
- Text("This is hint text")
- }, modifier = Modifier.weight(1f).fillMaxHeight(), placeholder = {
- Text("Placeholder")
- })
+ TextArea(
+ text4,
+ { text4 = it },
+ modifier = Modifier.weight(1f),
+ outline = Outline.Warning,
+ placeholder = { Text("Text area with warning") },
+ )
}
}
diff --git a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextFields.kt b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextFields.kt
index d6955b1aea7d..5fcf04f32db3 100644
--- a/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextFields.kt
+++ b/platform/jewel/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/components/TextFields.kt
@@ -11,6 +11,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.GroupHeader
import org.jetbrains.jewel.LabelledTextField
+import org.jetbrains.jewel.Outline
import org.jetbrains.jewel.Text
import org.jetbrains.jewel.TextField
@@ -19,34 +20,43 @@ fun TextFields() {
GroupHeader("TextFields")
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
) {
var text1 by remember { mutableStateOf("TextField") }
TextField(text1, { text1 = it })
- var text2 by remember { mutableStateOf("Error hinted") }
- TextField(text2, { text2 = it }, isError = true)
+ var text2 by remember { mutableStateOf("") }
+ TextField(text2, { text2 = it }, placeholder = { Text("Placeholder") })
- var text3 by remember { mutableStateOf("Disabled") }
- TextField(text3, { text3 = it }, enabled = false)
+ var text3 by remember { mutableStateOf("") }
+ TextField(text3, { text3 = it }, outline = Outline.Error, placeholder = { Text("Error outline") })
var text4 by remember { mutableStateOf("") }
- TextField(text4, { text4 = it }, placeholder = {
- Text("Placeholder")
- })
- }
- Row(
- horizontalArrangement = Arrangement.spacedBy(10.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- var text1 by remember { mutableStateOf("Labelled TextField") }
- LabelledTextField({
- Text("Label:")
- }, text1, { text1 = it })
+ TextField(text4, { text4 = it }, outline = Outline.Warning, placeholder = { Text("Warning outline") })
- var text2 by remember { mutableStateOf("Labelled TextField with hint") }
- LabelledTextField({
- Text("Label:")
- }, text2, { text2 = it }, hint = { Text("Attached hint text") })
+ var text5 by remember { mutableStateOf("Disabled") }
+ TextField(text5, { text5 = it }, enabled = false)
+ }
+
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
+ verticalAlignment = Alignment.Top,
+ ) {
+ var text1 by remember { mutableStateOf("") }
+ LabelledTextField(
+ value = text1,
+ onValueChange = { text1 = it },
+ label = { Text("Label:") },
+ placeholder = { Text("Labelled TextField") },
+ )
+
+ var text2 by remember { mutableStateOf("") }
+ LabelledTextField(
+ value = text2,
+ onValueChange = { text2 = it },
+ label = { Text("Label:") },
+ hint = { Text("Attached hint text") },
+ placeholder = { Text("Labelled TextField with hint") },
+ )
}
}
diff --git a/platform/jewel/settings.gradle.kts b/platform/jewel/settings.gradle.kts
index dee0da05f11f..fb82b11f0366 100644
--- a/platform/jewel/settings.gradle.kts
+++ b/platform/jewel/settings.gradle.kts
@@ -26,10 +26,10 @@ dependencyResolutionManagement {
include(
":core",
- ":foundation",
":compose-utils",
-// ":ide-laf-bridge",
+ ":ide-laf-bridge",
":samples:standalone",
+ ":samples:ide-plugin",
":themes:int-ui:int-ui-core",
":themes:int-ui:int-ui-standalone",
)
diff --git a/platform/jewel/themes/int-ui/int-ui-core/build.gradle.kts b/platform/jewel/themes/int-ui/int-ui-core/build.gradle.kts
index 7f57a69fc7ae..ae05a9577549 100644
--- a/platform/jewel/themes/int-ui/int-ui-core/build.gradle.kts
+++ b/platform/jewel/themes/int-ui/int-ui-core/build.gradle.kts
@@ -9,7 +9,6 @@ plugins {
dependencies {
api(projects.core)
api(projects.composeUtils)
- api(projects.foundation)
}
intelliJThemeGenerator {
diff --git a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/BaseIntUiTheme.kt b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/BaseIntUiTheme.kt
index aa124e4348a5..0e090974ecd4 100644
--- a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/BaseIntUiTheme.kt
+++ b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/BaseIntUiTheme.kt
@@ -4,8 +4,8 @@ import androidx.compose.foundation.LocalContextMenuRepresentation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
-import org.jetbrains.jewel.ExperimentalJewelApi
import org.jetbrains.jewel.GlobalColors
import org.jetbrains.jewel.GlobalMetrics
import org.jetbrains.jewel.IntelliJComponentStyling
@@ -67,6 +67,11 @@ interface BaseIntUiTheme : IntelliJTheme {
@ReadOnlyComposable
get() = IntelliJTheme.defaultTextStyle
+ val contentColor: Color
+ @Composable
+ @ReadOnlyComposable
+ get() = IntelliJTheme.contentColor
+
val isDark: Boolean
@Composable
@ReadOnlyComposable
@@ -173,13 +178,15 @@ interface BaseIntUiTheme : IntelliJTheme {
get() = IntelliJTheme.editorTabStyle
}
-@OptIn(ExperimentalJewelApi::class)
@Composable
-fun BaseIntUiTheme(theme: IntUiThemeDefinition, componentStyling: IntelliJComponentStyling, content: @Composable () -> Unit) {
+fun BaseIntUiTheme(
+ theme: IntUiThemeDefinition,
+ componentStyling: IntelliJComponentStyling,
+ content: @Composable () -> Unit,
+) {
BaseIntUiTheme(theme, componentStyling, swingCompatMode = false, content)
}
-@ExperimentalJewelApi
@Composable
fun BaseIntUiTheme(
theme: IntUiThemeDefinition,
@@ -207,7 +214,7 @@ fun BaseIntUiTheme(
LocalTextAreaStyle provides componentStyling.textAreaStyle,
LocalTextFieldStyle provides componentStyling.textFieldStyle,
LocalDefaultTabStyle provides componentStyling.defaultTabStyle,
- LocalEditorTabStyle provides componentStyling.editorTabStyle
+ LocalEditorTabStyle provides componentStyling.editorTabStyle,
) {
IntelliJTheme(theme, swingCompatMode, content)
}
diff --git a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeColorPalette.kt b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeColorPalette.kt
index b2ebfdc19d64..9820621e21dd 100644
--- a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeColorPalette.kt
+++ b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeColorPalette.kt
@@ -1,8 +1,10 @@
package org.jetbrains.jewel.themes.intui.core
+import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
import org.jetbrains.jewel.IntelliJThemeColorPalette
+@Immutable
interface IntUiThemeColorPalette : IntelliJThemeColorPalette {
fun grey(): List
diff --git a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeDefinition.kt b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeDefinition.kt
index cc7c999bbe26..ccf43386b7d1 100644
--- a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeDefinition.kt
+++ b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntUiThemeDefinition.kt
@@ -1,16 +1,49 @@
package org.jetbrains.jewel.themes.intui.core
+import androidx.compose.runtime.Immutable
import androidx.compose.ui.text.TextStyle
import org.jetbrains.jewel.GlobalColors
import org.jetbrains.jewel.GlobalMetrics
import org.jetbrains.jewel.IntelliJThemeDefinition
import org.jetbrains.jewel.IntelliJThemeIconData
-data class IntUiThemeDefinition(
+@Immutable
+class IntUiThemeDefinition(
override val isDark: Boolean,
override val globalColors: GlobalColors,
override val colorPalette: IntUiThemeColorPalette,
override val iconData: IntelliJThemeIconData,
- override val metrics: GlobalMetrics,
+ override val globalMetrics: GlobalMetrics,
override val defaultTextStyle: TextStyle,
-) : IntelliJThemeDefinition
+) : IntelliJThemeDefinition {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as IntUiThemeDefinition
+
+ if (isDark != other.isDark) return false
+ if (globalColors != other.globalColors) return false
+ if (colorPalette != other.colorPalette) return false
+ if (iconData != other.iconData) return false
+ if (globalMetrics != other.globalMetrics) return false
+ if (defaultTextStyle != other.defaultTextStyle) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = isDark.hashCode()
+ result = 31 * result + globalColors.hashCode()
+ result = 31 * result + colorPalette.hashCode()
+ result = 31 * result + iconData.hashCode()
+ result = 31 * result + globalMetrics.hashCode()
+ result = 31 * result + defaultTextStyle.hashCode()
+ return result
+ }
+
+ override fun toString(): String =
+ "IntUiThemeDefinition(isDark=$isDark, globalColors=$globalColors, colorPalette=$colorPalette, " +
+ "iconData=$iconData, metrics=$globalMetrics, defaultTextStyle=$defaultTextStyle)"
+}
diff --git a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntelliJSvgPatcher.kt b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntelliJSvgPatcher.kt
index 54a5cdcbf6e0..2a5da73d5a5b 100644
--- a/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntelliJSvgPatcher.kt
+++ b/platform/jewel/themes/int-ui/int-ui-core/src/main/kotlin/org/jetbrains/jewel/themes/intui/core/IntelliJSvgPatcher.kt
@@ -94,28 +94,28 @@ class IntelliJSvgPatcher(private val mapper: PaletteMapper) : SvgPatcher {
red = rawColor.substring(startPos, startPos + 1).toInt(16),
green = rawColor.substring(startPos + 1, startPos + 2).toInt(16),
blue = rawColor.substring(startPos + 2, startPos + 3).toInt(16),
- alpha = alphaOverride ?: 255
+ alpha = alphaOverride ?: 255,
)
4 -> Color(
red = rawColor.substring(startPos, startPos + 1).toInt(16),
green = rawColor.substring(startPos + 1, startPos + 2).toInt(16),
blue = rawColor.substring(startPos + 2, startPos + 3).toInt(16),
- alpha = alphaOverride ?: rawColor.substring(startPos + 3, startPos + 4).toInt(16)
+ alpha = alphaOverride ?: rawColor.substring(startPos + 3, startPos + 4).toInt(16),
)
6 -> Color(
red = rawColor.substring(startPos, startPos + 2).toInt(16),
green = rawColor.substring(startPos + 2, startPos + 4).toInt(16),
blue = rawColor.substring(startPos + 4, startPos + 6).toInt(16),
- alpha = alphaOverride ?: 255
+ alpha = alphaOverride ?: 255,
)
8 -> Color(
red = rawColor.substring(startPos, startPos + 2).toInt(16),
green = rawColor.substring(startPos + 2, startPos + 4).toInt(16),
blue = rawColor.substring(startPos + 4, startPos + 6).toInt(16),
- alpha = alphaOverride ?: rawColor.substring(startPos + 6, startPos + 8).toInt(16)
+ alpha = alphaOverride ?: rawColor.substring(startPos + 6, startPos + 8).toInt(16),
)
else -> null
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiDefaultResourceLoader.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiDefaultResourceLoader.kt
index 840037da0638..f28df3438adb 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiDefaultResourceLoader.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiDefaultResourceLoader.kt
@@ -1,14 +1,16 @@
package org.jetbrains.jewel.themes.intui.standalone
import androidx.compose.ui.res.ResourceLoader
+import org.jetbrains.jewel.JewelResourceLoader
import java.io.InputStream
-object IntUiDefaultResourceLoader : ResourceLoader {
+object IntUiDefaultResourceLoader : ResourceLoader, JewelResourceLoader {
+
+ override val searchClasses = listOf(IntUiTheme::class.java, IntUiDefaultResourceLoader::class.java)
override fun load(resourcePath: String): InputStream {
val normalizedPath = if (!resourcePath.startsWith("/")) "/$resourcePath" else resourcePath
- val resource = IntUiTheme::class.java.getResourceAsStream(normalizedPath)
- ?: IntUiDefaultResourceLoader::class.java.getResourceAsStream(normalizedPath)
+ val resource = searchClasses.firstNotNullOfOrNull { it.getResourceAsStream(normalizedPath) }
return requireNotNull(resource) { "Resource $resourcePath not found" }
}
}
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalColors.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalColors.kt
index f8f6a4ab433e..1ea2411a73e5 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalColors.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalColors.kt
@@ -6,7 +6,6 @@ import androidx.compose.ui.graphics.Color
import org.jetbrains.jewel.BorderColors
import org.jetbrains.jewel.GlobalColors
import org.jetbrains.jewel.OutlineColors
-import org.jetbrains.jewel.SwingLafKey
import org.jetbrains.jewel.themes.intui.core.theme.IntUiDarkTheme
import org.jetbrains.jewel.themes.intui.core.theme.IntUiLightTheme
@@ -14,7 +13,7 @@ import org.jetbrains.jewel.themes.intui.core.theme.IntUiLightTheme
class IntUiGlobalColors(
override val borders: BorderColors,
override val outlines: OutlineColors,
- @SwingLafKey("*.infoForeground") override val infoContent: Color,
+ override val infoContent: Color,
) : GlobalColors {
override fun equals(other: Any?): Boolean {
@@ -46,31 +45,31 @@ class IntUiGlobalColors(
fun light(
borders: BorderColors = IntUiBorderColors.light(),
outlines: OutlineColors = IntUiOutlineColors.light(),
- @SwingLafKey("*.infoForeground") infoContent: Color = IntUiTheme.colorPalette.grey(7),
+ infoContent: Color = IntUiTheme.colorPalette.grey(7),
) = IntUiGlobalColors(
borders = borders,
outlines = outlines,
- infoContent = infoContent
+ infoContent = infoContent,
)
@Composable
fun dark(
borders: BorderColors = IntUiBorderColors.dark(),
outlines: OutlineColors = IntUiOutlineColors.dark(),
- @SwingLafKey("*.infoForeground") infoContent: Color = IntUiTheme.colorPalette.grey(7),
+ infoContent: Color = IntUiTheme.colorPalette.grey(7),
) = IntUiGlobalColors(
borders = borders,
outlines = outlines,
- infoContent = infoContent
+ infoContent = infoContent,
)
}
}
@Immutable
class IntUiBorderColors(
- @SwingLafKey("Component.borderColor") override val normal: Color,
- @SwingLafKey("Component.focusedBorderColor") override val focused: Color,
- @SwingLafKey("*.disabledBorderColor") override val disabled: Color,
+ override val normal: Color,
+ override val focused: Color,
+ override val disabled: Color,
) : BorderColors {
override fun equals(other: Any?): Boolean {
@@ -116,11 +115,11 @@ class IntUiBorderColors(
@Immutable
class IntUiOutlineColors(
- @SwingLafKey("*.focusColor") override val focused: Color,
- @SwingLafKey("Component.warningFocusColor") override val focusedWarning: Color,
- @SwingLafKey("Component.errorFocusColor") override val focusedError: Color,
- @SwingLafKey("Component.inactiveWarningFocusColor") override val warning: Color,
- @SwingLafKey("Component.inactiveErrorFocusColor") override val error: Color,
+ override val focused: Color,
+ override val focusedWarning: Color,
+ override val focusedError: Color,
+ override val warning: Color,
+ override val error: Color,
) : OutlineColors {
override fun equals(other: Any?): Boolean {
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalMetrics.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalMetrics.kt
index daae555daab9..62fb8698af12 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalMetrics.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiGlobalMetrics.kt
@@ -1,13 +1,26 @@
package org.jetbrains.jewel.themes.intui.standalone
-import androidx.compose.foundation.shape.CornerSize
import androidx.compose.runtime.Immutable
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.GlobalMetrics
@Immutable
-data class IntUiGlobalMetrics(
+class IntUiGlobalMetrics(
override val outlineWidth: Dp = 2.dp,
- override val outlineCornerSize: CornerSize = CornerSize(3.dp),
-) : GlobalMetrics
+) : GlobalMetrics {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as IntUiGlobalMetrics
+
+ return outlineWidth == other.outlineWidth
+ }
+
+ override fun hashCode(): Int = outlineWidth.hashCode()
+
+ override fun toString(): String =
+ "IntUiGlobalMetrics(outlineWidth=$outlineWidth)"
+}
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiTheme.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiTheme.kt
index 6a40a89b552e..9fc0b80bf873 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiTheme.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/IntUiTheme.kt
@@ -10,12 +10,18 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
-import org.jetbrains.jewel.ExperimentalJewelApi
import org.jetbrains.jewel.GlobalColors
import org.jetbrains.jewel.GlobalMetrics
import org.jetbrains.jewel.IntelliJComponentStyling
+import org.jetbrains.jewel.IntelliJSvgLoader
import org.jetbrains.jewel.IntelliJThemeIconData
+import org.jetbrains.jewel.LocalColorPalette
+import org.jetbrains.jewel.LocalContentColor
+import org.jetbrains.jewel.LocalGlobalColors
+import org.jetbrains.jewel.LocalGlobalMetrics
+import org.jetbrains.jewel.LocalIconData
import org.jetbrains.jewel.LocalResourceLoader
+import org.jetbrains.jewel.LocalTextStyle
import org.jetbrains.jewel.SvgLoader
import org.jetbrains.jewel.styling.ButtonStyle
import org.jetbrains.jewel.styling.CheckboxStyle
@@ -35,7 +41,6 @@ import org.jetbrains.jewel.themes.PaletteMapperFactory
import org.jetbrains.jewel.themes.intui.core.BaseIntUiTheme
import org.jetbrains.jewel.themes.intui.core.IntUiThemeColorPalette
import org.jetbrains.jewel.themes.intui.core.IntUiThemeDefinition
-import org.jetbrains.jewel.themes.intui.core.IntelliJSvgLoader
import org.jetbrains.jewel.themes.intui.core.IntelliJSvgPatcher
import org.jetbrains.jewel.themes.intui.core.theme.IntUiDarkTheme
import org.jetbrains.jewel.themes.intui.core.theme.IntUiLightTheme
@@ -62,7 +67,7 @@ object IntUiTheme : BaseIntUiTheme {
fontFamily = FontFamily.Inter,
fontSize = 13.sp,
fontWeight = FontWeight.Normal,
- fontStyle = FontStyle.Normal
+ fontStyle = FontStyle.Normal,
)
override val defaultLightTextStyle = intUiDefaultTextStyle.copy(color = IntUiLightTheme.colors.grey(1))
@@ -87,8 +92,20 @@ object IntUiTheme : BaseIntUiTheme {
) = IntUiThemeDefinition(isDark = true, colors, palette, icons, metrics, defaultTextStyle)
@Composable
- fun defaultComponentStyling(isDark: Boolean, svgLoader: SvgLoader) =
- if (isDark) darkComponentStyling(svgLoader) else lightComponentStyling(svgLoader)
+ fun defaultComponentStyling(theme: IntUiThemeDefinition, svgLoader: SvgLoader): IntelliJComponentStyling {
+ lateinit var styling: IntelliJComponentStyling
+ CompositionLocalProvider(
+ LocalColorPalette provides theme.colorPalette,
+ LocalTextStyle provides theme.defaultTextStyle,
+ LocalContentColor provides theme.defaultTextStyle.color,
+ LocalIconData provides theme.iconData,
+ LocalGlobalColors provides theme.globalColors,
+ LocalGlobalMetrics provides theme.globalMetrics,
+ ) {
+ styling = if (theme.isDark) darkComponentStyling(svgLoader) else lightComponentStyling(svgLoader)
+ }
+ return styling
+ }
@Composable
fun darkComponentStyling(
@@ -101,34 +118,34 @@ object IntUiTheme : BaseIntUiTheme {
groupHeaderStyle: GroupHeaderStyle = IntUiGroupHeaderStyle.dark(),
labelledTextFieldStyle: LabelledTextFieldStyle = IntUiLabelledTextFieldStyle.dark(),
linkStyle: LinkStyle = IntUiLinkStyle.dark(svgLoader),
- menuStyle: MenuStyle = IntUiMenuStyle.dark(),
+ menuStyle: MenuStyle = IntUiMenuStyle.dark(svgLoader),
horizontalProgressBarStyle: HorizontalProgressBarStyle = IntUiHorizontalProgressBarStyle.dark(),
radioButtonStyle: RadioButtonStyle = IntUiRadioButtonStyle.dark(svgLoader),
scrollbarStyle: ScrollbarStyle = IntUiScrollbarStyle.dark(),
textAreaStyle: IntUiTextAreaStyle = IntUiTextAreaStyle.dark(),
textFieldStyle: TextFieldStyle = IntUiTextFieldStyle.dark(),
- lazyTreeStyle: LazyTreeStyle = IntUiLazyTreeStyle.dark(),
+ lazyTreeStyle: LazyTreeStyle = IntUiLazyTreeStyle.dark(svgLoader),
defaultTabStyle: TabStyle = IntUiTabStyle.Default.dark(svgLoader),
editorTabStyle: TabStyle = IntUiTabStyle.Editor.dark(svgLoader),
) =
IntelliJComponentStyling(
- defaultButtonStyle = defaultButtonStyle,
- outlinedButtonStyle = outlinedButtonStyle,
checkboxStyle = checkboxStyle,
chipStyle = chipStyle,
+ defaultButtonStyle = defaultButtonStyle,
+ defaultTabStyle = defaultTabStyle,
dropdownStyle = dropdownStyle,
+ editorTabStyle = editorTabStyle,
groupHeaderStyle = groupHeaderStyle,
+ horizontalProgressBarStyle = horizontalProgressBarStyle,
labelledTextFieldStyle = labelledTextFieldStyle,
+ lazyTreeStyle = lazyTreeStyle,
linkStyle = linkStyle,
menuStyle = menuStyle,
- horizontalProgressBarStyle = horizontalProgressBarStyle,
+ outlinedButtonStyle = outlinedButtonStyle,
radioButtonStyle = radioButtonStyle,
scrollbarStyle = scrollbarStyle,
textAreaStyle = textAreaStyle,
textFieldStyle = textFieldStyle,
- lazyTreeStyle = lazyTreeStyle,
- defaultTabStyle = defaultTabStyle,
- editorTabStyle = editorTabStyle
)
@Composable
@@ -142,51 +159,54 @@ object IntUiTheme : BaseIntUiTheme {
groupHeaderStyle: GroupHeaderStyle = IntUiGroupHeaderStyle.light(),
labelledTextFieldStyle: LabelledTextFieldStyle = IntUiLabelledTextFieldStyle.light(),
linkStyle: LinkStyle = IntUiLinkStyle.light(svgLoader),
- menuStyle: MenuStyle = IntUiMenuStyle.light(),
+ menuStyle: MenuStyle = IntUiMenuStyle.light(svgLoader),
horizontalProgressBarStyle: HorizontalProgressBarStyle = IntUiHorizontalProgressBarStyle.light(),
radioButtonStyle: RadioButtonStyle = IntUiRadioButtonStyle.light(svgLoader),
scrollbarStyle: ScrollbarStyle = IntUiScrollbarStyle.light(),
textAreaStyle: IntUiTextAreaStyle = IntUiTextAreaStyle.light(),
textFieldStyle: TextFieldStyle = IntUiTextFieldStyle.light(),
- lazyTreeStyle: LazyTreeStyle = IntUiLazyTreeStyle.light(),
+ lazyTreeStyle: LazyTreeStyle = IntUiLazyTreeStyle.light(svgLoader),
defaultTabStyle: TabStyle = IntUiTabStyle.Default.light(svgLoader),
editorTabStyle: TabStyle = IntUiTabStyle.Editor.light(svgLoader),
) =
IntelliJComponentStyling(
- defaultButtonStyle = defaultButtonStyle,
- outlinedButtonStyle = outlinedButtonStyle,
checkboxStyle = checkboxStyle,
chipStyle = chipStyle,
+ defaultButtonStyle = defaultButtonStyle,
+ defaultTabStyle = defaultTabStyle,
dropdownStyle = dropdownStyle,
+ editorTabStyle = editorTabStyle,
groupHeaderStyle = groupHeaderStyle,
+ horizontalProgressBarStyle = horizontalProgressBarStyle,
labelledTextFieldStyle = labelledTextFieldStyle,
+ lazyTreeStyle = lazyTreeStyle,
linkStyle = linkStyle,
menuStyle = menuStyle,
- horizontalProgressBarStyle = horizontalProgressBarStyle,
+ outlinedButtonStyle = outlinedButtonStyle,
radioButtonStyle = radioButtonStyle,
scrollbarStyle = scrollbarStyle,
textAreaStyle = textAreaStyle,
textFieldStyle = textFieldStyle,
- lazyTreeStyle = lazyTreeStyle,
- defaultTabStyle = defaultTabStyle,
- editorTabStyle = editorTabStyle
)
}
-@OptIn(ExperimentalJewelApi::class)
@Composable
-fun IntUiTheme(theme: IntUiThemeDefinition, swingCompatMode: Boolean = false, content: @Composable () -> Unit) {
- val svgLoader by remember(theme.isDark, theme.iconData, theme.colorPalette) {
- val paletteMapper = PaletteMapperFactory.create(theme.isDark, theme.iconData, theme.colorPalette)
+fun IntUiTheme(
+ themeDefinition: IntUiThemeDefinition,
+ swingCompatMode: Boolean = false,
+ content: @Composable () -> Unit,
+) {
+ val svgLoader by remember(themeDefinition.isDark, themeDefinition.iconData, themeDefinition.colorPalette) {
+ val paletteMapper =
+ PaletteMapperFactory.create(themeDefinition.isDark, themeDefinition.iconData, themeDefinition.colorPalette)
val svgPatcher = IntelliJSvgPatcher(paletteMapper)
mutableStateOf(IntelliJSvgLoader(svgPatcher))
}
- val componentStyling = defaultComponentStyling(theme.isDark, svgLoader)
- IntUiTheme(theme, componentStyling, swingCompatMode, content)
+ val componentStyling = defaultComponentStyling(themeDefinition, svgLoader)
+ IntUiTheme(themeDefinition, componentStyling, swingCompatMode, content)
}
-@ExperimentalJewelApi
@Composable
fun IntUiTheme(
theme: IntUiThemeDefinition,
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/InterFont.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/InterFont.kt
index 8d5000e53cb6..5d1b8ab48883 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/InterFont.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/InterFont.kt
@@ -4,34 +4,17 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.platform.Font
-private val InterRegular = Font(resource = "/fonts/inter/Inter-Regular.ttf", weight = FontWeight.Normal)
-
-private val InterBold = Font(resource = "/fonts/inter/Inter-Bold.ttf", weight = FontWeight.Bold)
-
-private val InterMedium = Font(resource = "/fonts/inter/Inter-Medium.ttf", weight = FontWeight.Medium)
-
-private val InterSemiBold = Font(resource = "/fonts/inter/Inter-SemiBold.ttf", weight = FontWeight.SemiBold)
-
-private val InterLight = Font(resource = "/fonts/inter/Inter-Light.ttf", weight = FontWeight.Light)
-
-private val InterThin = Font(resource = "/fonts/inter/Inter-Thin.ttf", weight = FontWeight.Thin)
-
-private val InterExtraLight = Font(resource = "/fonts/inter/Inter-ExtraLight.ttf", weight = FontWeight.ExtraLight)
-
-private val InterExtraBold = Font(resource = "/fonts/inter/Inter-ExtraBold.ttf", weight = FontWeight.ExtraBold)
-
-private val InterBlack = Font(resource = "/fonts/inter/Inter-Black.ttf", weight = FontWeight.Black)
-
-private val Inter = FontFamily(
- InterRegular,
- InterBold,
- InterMedium,
- InterSemiBold,
- InterLight,
- InterThin,
- InterExtraLight,
- InterExtraBold
+private val InterFontFamily = FontFamily(
+ Font(resource = "/fonts/inter/Inter-Thin.ttf", weight = FontWeight.Thin),
+ Font(resource = "/fonts/inter/Inter-ExtraLight.ttf", weight = FontWeight.ExtraLight),
+ Font(resource = "/fonts/inter/Inter-Light.ttf", weight = FontWeight.Light),
+ Font(resource = "/fonts/inter/Inter-Regular.ttf", weight = FontWeight.Normal),
+ Font(resource = "/fonts/inter/Inter-Medium.ttf", weight = FontWeight.Medium),
+ Font(resource = "/fonts/inter/Inter-SemiBold.ttf", weight = FontWeight.SemiBold),
+ Font(resource = "/fonts/inter/Inter-Bold.ttf", weight = FontWeight.Bold),
+ Font(resource = "/fonts/inter/Inter-ExtraBold.ttf", weight = FontWeight.ExtraBold),
+ Font(resource = "/fonts/inter/Inter-Black.ttf", weight = FontWeight.Black),
)
val FontFamily.Companion.Inter
- get() = org.jetbrains.jewel.themes.intui.standalone.Inter
+ get() = InterFontFamily
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiButtonStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiButtonStyling.kt
index de2a5dc6d98c..7c7b157c46c0 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiButtonStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiButtonStyling.kt
@@ -67,11 +67,11 @@ data class IntUiButtonColors(
override val contentFocused: Color,
override val contentPressed: Color,
override val contentHovered: Color,
- override val border: Color,
- override val borderDisabled: Color,
- override val borderFocused: Color,
- override val borderPressed: Color,
- override val borderHovered: Color,
+ override val border: Brush,
+ override val borderDisabled: Brush,
+ override val borderFocused: Brush,
+ override val borderPressed: Brush,
+ override val borderHovered: Brush,
) : ButtonColors {
object Default {
@@ -88,11 +88,11 @@ data class IntUiButtonColors(
contentFocused: Color = IntUiLightTheme.colors.grey(14),
contentPressed: Color = IntUiLightTheme.colors.grey(14),
contentHovered: Color = IntUiLightTheme.colors.grey(14),
- border: Color = Color.Unspecified,
- borderDisabled: Color = Color.Unspecified,
- borderFocused: Color = Color.Unspecified,
- borderPressed: Color = Color.Unspecified,
- borderHovered: Color = Color.Unspecified,
+ border: Brush = SolidColor(IntUiLightTheme.colors.blue(4)),
+ borderDisabled: Brush = SolidColor(IntUiLightTheme.colors.grey(11)),
+ borderFocused: Brush = SolidColor(IntUiLightTheme.colors.blue(4)),
+ borderPressed: Brush = border,
+ borderHovered: Brush = border,
) = IntUiButtonColors(
background,
backgroundDisabled,
@@ -108,7 +108,7 @@ data class IntUiButtonColors(
borderDisabled,
borderFocused,
borderPressed,
- borderHovered
+ borderHovered,
)
@Composable
@@ -123,11 +123,11 @@ data class IntUiButtonColors(
contentFocused: Color = IntUiDarkTheme.colors.grey(14),
contentPressed: Color = IntUiDarkTheme.colors.grey(14),
contentHovered: Color = IntUiDarkTheme.colors.grey(14),
- border: Color = Color.Unspecified,
- borderDisabled: Color = Color.Unspecified,
- borderFocused: Color = Color.Unspecified,
- borderPressed: Color = Color.Unspecified,
- borderHovered: Color = Color.Unspecified,
+ border: Brush = SolidColor(IntUiDarkTheme.colors.blue(6)),
+ borderDisabled: Brush = SolidColor(IntUiDarkTheme.colors.grey(4)),
+ borderFocused: Brush = SolidColor(IntUiDarkTheme.colors.grey(1)),
+ borderPressed: Brush = border,
+ borderHovered: Brush = border,
) = IntUiButtonColors(
background,
backgroundDisabled,
@@ -143,7 +143,7 @@ data class IntUiButtonColors(
borderDisabled,
borderFocused,
borderPressed,
- borderHovered
+ borderHovered,
)
}
@@ -151,21 +151,21 @@ data class IntUiButtonColors(
@Composable
fun light(
- background: Brush = SolidColor(Color.Unspecified),
+ background: Brush = SolidColor(Color.Transparent),
backgroundDisabled: Brush = SolidColor(IntUiTheme.colorPalette.grey(12)),
- backgroundFocused: Brush = SolidColor(Color.Unspecified),
+ backgroundFocused: Brush = SolidColor(Color.Transparent),
backgroundPressed: Brush = SolidColor(IntUiTheme.colorPalette.grey(13)),
- backgroundHovered: Brush = SolidColor(Color.Unspecified),
+ backgroundHovered: Brush = SolidColor(Color.Transparent),
content: Color = IntUiTheme.colorPalette.grey(1),
contentDisabled: Color = IntUiTheme.colorPalette.grey(8),
contentFocused: Color = IntUiTheme.colorPalette.grey(1),
contentPressed: Color = IntUiTheme.colorPalette.grey(1),
contentHovered: Color = IntUiTheme.colorPalette.grey(1),
- border: Color = IntUiTheme.colorPalette.grey(9),
- borderDisabled: Color = Color.Unspecified,
- borderFocused: Color = IntUiTheme.colorPalette.blue(4),
- borderPressed: Color = IntUiTheme.colorPalette.grey(7),
- borderHovered: Color = IntUiTheme.colorPalette.grey(8),
+ border: Brush = SolidColor(IntUiTheme.colorPalette.grey(9)),
+ borderDisabled: Brush = SolidColor(IntUiTheme.colorPalette.blue(11)),
+ borderFocused: Brush = SolidColor(IntUiTheme.colorPalette.blue(4)),
+ borderPressed: Brush = SolidColor(IntUiTheme.colorPalette.grey(7)),
+ borderHovered: Brush = SolidColor(IntUiTheme.colorPalette.grey(8)),
) = IntUiButtonColors(
background,
backgroundDisabled,
@@ -181,12 +181,12 @@ data class IntUiButtonColors(
borderDisabled,
borderFocused,
borderPressed,
- borderHovered
+ borderHovered,
)
@Composable
fun dark(
- background: Brush = SolidColor(Color.Unspecified),
+ background: Brush = SolidColor(Color.Transparent),
backgroundDisabled: Brush = SolidColor(IntUiTheme.colorPalette.grey(5)),
backgroundFocused: Brush = SolidColor(IntUiTheme.colorPalette.grey(6)),
backgroundPressed: Brush = SolidColor(IntUiTheme.colorPalette.grey(2)),
@@ -196,11 +196,11 @@ data class IntUiButtonColors(
contentFocused: Color = IntUiTheme.colorPalette.grey(12),
contentPressed: Color = IntUiTheme.colorPalette.grey(12),
contentHovered: Color = IntUiTheme.colorPalette.grey(12),
- border: Color = IntUiTheme.colorPalette.grey(5),
- borderDisabled: Color = Color.Unspecified,
- borderFocused: Color = IntUiTheme.colorPalette.blue(6),
- borderPressed: Color = IntUiTheme.colorPalette.grey(7),
- borderHovered: Color = IntUiTheme.colorPalette.grey(7),
+ border: Brush = SolidColor(IntUiTheme.colorPalette.grey(5)),
+ borderDisabled: Brush = SolidColor(IntUiTheme.colorPalette.blue(4)),
+ borderFocused: Brush = SolidColor(IntUiTheme.colorPalette.grey(2)),
+ borderPressed: Brush = SolidColor(IntUiTheme.colorPalette.grey(7)),
+ borderHovered: Brush = SolidColor(IntUiTheme.colorPalette.grey(7)),
) = IntUiButtonColors(
background,
backgroundDisabled,
@@ -216,7 +216,7 @@ data class IntUiButtonColors(
borderDisabled,
borderFocused,
borderPressed,
- borderHovered
+ borderHovered,
)
}
}
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiCheckboxStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiCheckboxStyling.kt
index 8a6aa79dfb4a..20a9441866d9 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiCheckboxStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiCheckboxStyling.kt
@@ -54,9 +54,6 @@ data class IntUiCheckboxColors(
override val content: Color,
override val contentDisabled: Color,
override val contentSelected: Color,
- override val checkboxBorder: Color,
- override val checkboxBorderDisabled: Color,
- override val checkboxBorderSelected: Color,
) : CheckboxColors {
companion object {
@@ -69,9 +66,6 @@ data class IntUiCheckboxColors(
content: Color = IntUiLightTheme.colors.grey(1),
contentDisabled: Color = IntUiLightTheme.colors.grey(8),
contentSelected: Color = content,
- checkboxBorder: Color = IntUiLightTheme.colors.grey(8),
- borderDisabled: Color = IntUiLightTheme.colors.grey(11),
- borderSelected: Color = IntUiLightTheme.colors.blue(4),
) = IntUiCheckboxColors(
background,
backgroundDisabled,
@@ -79,9 +73,6 @@ data class IntUiCheckboxColors(
content,
contentDisabled,
contentSelected,
- checkboxBorder,
- borderDisabled,
- borderSelected
)
@Composable
@@ -92,9 +83,6 @@ data class IntUiCheckboxColors(
content: Color = IntUiDarkTheme.colors.grey(12),
contentDisabled: Color = IntUiDarkTheme.colors.grey(7),
contentSelected: Color = content,
- checkboxBorder: Color = IntUiDarkTheme.colors.grey(6),
- borderDisabled: Color = IntUiDarkTheme.colors.grey(6),
- borderSelected: Color = Color.Unspecified,
) = IntUiCheckboxColors(
background,
backgroundDisabled,
@@ -102,9 +90,6 @@ data class IntUiCheckboxColors(
content,
contentDisabled,
contentSelected,
- checkboxBorder,
- borderDisabled,
- borderSelected
)
}
}
@@ -124,7 +109,6 @@ data class IntUiCheckboxIcons(
companion object {
- @Composable
fun checkbox(
svgLoader: SvgLoader,
basePath: String = "icons/intui/checkBox.svg",
@@ -134,12 +118,11 @@ data class IntUiCheckboxIcons(
svgLoader,
prefixTokensProvider = { state: CheckboxState ->
if (state.toggleableState == ToggleableState.Indeterminate) "Indeterminate" else ""
- }
+ },
)
}
}
-@Composable
fun intUiCheckboxIcons(
svgLoader: SvgLoader,
checkbox: StatefulPainterProvider = IntUiCheckboxIcons.checkbox(svgLoader),
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiChipStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiChipStyling.kt
index 6fb078896e42..5d0b92b0e9ef 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiChipStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiChipStyling.kt
@@ -9,7 +9,6 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.styling.ChipColors
import org.jetbrains.jewel.styling.ChipMetrics
@@ -46,16 +45,31 @@ data class IntUiChipColors(
override val backgroundFocused: Brush,
override val backgroundPressed: Brush,
override val backgroundHovered: Brush,
+ override val backgroundSelected: Brush,
+ override val backgroundSelectedDisabled: Brush,
+ override val backgroundSelectedPressed: Brush,
+ override val backgroundSelectedFocused: Brush,
+ override val backgroundSelectedHovered: Brush,
override val content: Color,
override val contentDisabled: Color,
override val contentFocused: Color,
override val contentPressed: Color,
override val contentHovered: Color,
+ override val contentSelected: Color,
+ override val contentSelectedDisabled: Color,
+ override val contentSelectedPressed: Color,
+ override val contentSelectedFocused: Color,
+ override val contentSelectedHovered: Color,
override val border: Color,
override val borderDisabled: Color,
override val borderFocused: Color,
override val borderPressed: Color,
override val borderHovered: Color,
+ override val borderSelected: Color,
+ override val borderSelectedDisabled: Color,
+ override val borderSelectedPressed: Color,
+ override val borderSelectedFocused: Color,
+ override val borderSelectedHovered: Color,
) : ChipColors {
companion object {
@@ -67,32 +81,62 @@ data class IntUiChipColors(
backgroundFocused: Brush = background,
backgroundPressed: Brush = SolidColor(IntUiLightTheme.colors.grey(13)),
backgroundHovered: Brush = background,
+ backgroundSelected: Brush = background,
+ backgroundSelectedDisabled: Brush = backgroundDisabled,
+ backgroundSelectedFocused: Brush = background,
+ backgroundSelectedPressed: Brush = background,
+ backgroundSelectedHovered: Brush = background,
content: Color = IntUiLightTheme.colors.grey(1),
contentDisabled: Color = IntUiLightTheme.colors.grey(8),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
+ contentSelected: Color = content,
+ contentSelectedDisabled: Color = contentDisabled,
+ contentSelectedFocused: Color = content,
+ contentSelectedPressed: Color = content,
+ contentSelectedHovered: Color = content,
border: Color = IntUiLightTheme.colors.grey(9),
borderDisabled: Color = IntUiLightTheme.colors.grey(6),
- borderFocused: Color = Color.Unspecified,
+ borderFocused: Color = IntUiLightTheme.colors.blue(4),
borderPressed: Color = IntUiLightTheme.colors.grey(7),
borderHovered: Color = IntUiLightTheme.colors.grey(8),
+ borderSelected: Color = IntUiLightTheme.colors.blue(4),
+ borderSelectedDisabled: Color = borderSelected,
+ borderSelectedFocused: Color = borderSelected,
+ borderSelectedPressed: Color = borderSelected,
+ borderSelectedHovered: Color = borderSelected,
) = IntUiChipColors(
background,
backgroundDisabled,
backgroundFocused,
backgroundPressed,
backgroundHovered,
+ backgroundSelected,
+ backgroundSelectedDisabled,
+ backgroundSelectedPressed,
+ backgroundSelectedFocused,
+ backgroundSelectedHovered,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
+ contentSelected,
+ contentSelectedDisabled,
+ contentSelectedPressed,
+ contentSelectedFocused,
+ contentSelectedHovered,
border,
borderDisabled,
borderFocused,
borderPressed,
- borderHovered
+ borderHovered,
+ borderSelected,
+ borderSelectedDisabled,
+ borderSelectedPressed,
+ borderSelectedFocused,
+ borderSelectedHovered,
)
@Composable
@@ -102,40 +146,70 @@ data class IntUiChipColors(
backgroundFocused: Brush = background,
backgroundPressed: Brush = background,
backgroundHovered: Brush = background,
+ backgroundSelected: Brush = background,
+ backgroundSelectedDisabled: Brush = backgroundDisabled,
+ backgroundSelectedFocused: Brush = background,
+ backgroundSelectedPressed: Brush = background,
+ backgroundSelectedHovered: Brush = background,
content: Color = IntUiDarkTheme.colors.grey(12),
contentDisabled: Color = IntUiDarkTheme.colors.grey(8),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
+ contentSelected: Color = content,
+ contentSelectedDisabled: Color = contentDisabled,
+ contentSelectedFocused: Color = content,
+ contentSelectedPressed: Color = content,
+ contentSelectedHovered: Color = content,
border: Color = IntUiDarkTheme.colors.grey(5),
borderDisabled: Color = IntUiDarkTheme.colors.grey(6),
- borderFocused: Color = Color.Unspecified,
+ borderFocused: Color = IntUiDarkTheme.colors.blue(6),
borderPressed: Color = IntUiDarkTheme.colors.grey(7),
borderHovered: Color = borderPressed,
+ borderSelected: Color = IntUiDarkTheme.colors.blue(6),
+ borderSelectedDisabled: Color = borderSelected,
+ borderSelectedFocused: Color = borderSelected,
+ borderSelectedPressed: Color = borderSelected,
+ borderSelectedHovered: Color = borderSelected,
) = IntUiChipColors(
background,
backgroundDisabled,
backgroundFocused,
backgroundPressed,
backgroundHovered,
+ backgroundSelected,
+ backgroundSelectedDisabled,
+ backgroundSelectedPressed,
+ backgroundSelectedFocused,
+ backgroundSelectedHovered,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
+ contentSelected,
+ contentSelectedDisabled,
+ contentSelectedPressed,
+ contentSelectedFocused,
+ contentSelectedHovered,
border,
borderDisabled,
borderFocused,
borderPressed,
- borderHovered
+ borderHovered,
+ borderSelected,
+ borderSelectedDisabled,
+ borderSelectedPressed,
+ borderSelectedFocused,
+ borderSelectedHovered,
)
}
}
@Stable
data class IntUiChipMetrics(
- override val minSize: DpSize = DpSize(80.dp, 40.dp),
override val cornerSize: CornerSize = CornerSize(100),
- override val padding: PaddingValues = PaddingValues(4.dp),
+ override val padding: PaddingValues = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
override val borderWidth: Dp = 1.dp,
+ override val borderWidthSelected: Dp = 2.dp,
) : ChipMetrics
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiDropdownStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiDropdownStyling.kt
index bf44e777058a..43fafc82e48c 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiDropdownStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiDropdownStyling.kt
@@ -41,7 +41,7 @@ data class IntUiDropdownStyle(
metrics: IntUiDropdownMetrics = IntUiDropdownMetrics(),
icons: IntUiDropdownIcons = intUiDropdownIcons(svgLoader),
textStyle: TextStyle = IntUiTheme.defaultLightTextStyle,
- menuStyle: MenuStyle = IntUiMenuStyle.light(),
+ menuStyle: MenuStyle = IntUiMenuStyle.light(svgLoader),
) = IntUiDropdownStyle(colors, metrics, icons, textStyle, menuStyle)
@Composable
@@ -51,7 +51,7 @@ data class IntUiDropdownStyle(
metrics: IntUiDropdownMetrics = IntUiDropdownMetrics(),
icons: IntUiDropdownIcons = intUiDropdownIcons(svgLoader),
textStyle: TextStyle = IntUiTheme.defaultDarkTextStyle,
- menuStyle: MenuStyle = IntUiMenuStyle.dark(),
+ menuStyle: MenuStyle = IntUiMenuStyle.dark(svgLoader),
) = IntUiDropdownStyle(colors, metrics, icons, textStyle, menuStyle)
}
}
@@ -63,34 +63,24 @@ data class IntUiDropdownColors(
override val backgroundFocused: Color,
override val backgroundPressed: Color,
override val backgroundHovered: Color,
- override val backgroundWarning: Color,
- override val backgroundError: Color,
override val content: Color,
override val contentDisabled: Color,
override val contentFocused: Color,
override val contentPressed: Color,
override val contentHovered: Color,
- override val contentWarning: Color,
- override val contentError: Color,
override val border: Color,
override val borderDisabled: Color,
override val borderFocused: Color,
override val borderPressed: Color,
override val borderHovered: Color,
- override val borderWarning: Color,
- override val borderError: Color,
override val iconTint: Color,
override val iconTintDisabled: Color,
override val iconTintFocused: Color,
override val iconTintPressed: Color,
override val iconTintHovered: Color,
- override val iconTintWarning: Color,
- override val iconTintError: Color,
) : DropdownColors {
companion object {
- // TODO error and warning colors are probably wrong (and no distinction between focused
- // and unfocused is currently modeled, but it exists in Swing)
@Composable
fun light(
@@ -99,58 +89,42 @@ data class IntUiDropdownColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiLightTheme.colors.grey(1),
contentDisabled: Color = IntUiLightTheme.colors.grey(8),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiLightTheme.colors.grey(9),
borderDisabled: Color = IntUiLightTheme.colors.grey(11),
borderFocused: Color = IntUiLightTheme.colors.blue(4),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiLightTheme.colors.yellow(4),
- borderError: Color = IntUiLightTheme.colors.red(4),
iconTint: Color = IntUiLightTheme.colors.grey(7),
iconTintDisabled: Color = IntUiLightTheme.colors.grey(9),
iconTintFocused: Color = iconTint,
iconTintPressed: Color = iconTint,
iconTintHovered: Color = iconTint,
- iconTintWarning: Color = iconTint,
- iconTintError: Color = iconTint,
) = IntUiDropdownColors(
background,
backgroundDisabled,
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
iconTint,
iconTintDisabled,
iconTintFocused,
iconTintPressed,
iconTintHovered,
- iconTintWarning,
- iconTintError
)
@Composable
@@ -160,67 +134,52 @@ data class IntUiDropdownColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiDarkTheme.colors.grey(12),
contentDisabled: Color = IntUiDarkTheme.colors.grey(7),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiDarkTheme.colors.grey(5),
borderDisabled: Color = IntUiDarkTheme.colors.grey(11),
borderFocused: Color = IntUiDarkTheme.colors.blue(6),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiDarkTheme.colors.yellow(4),
- borderError: Color = IntUiDarkTheme.colors.red(4),
iconTint: Color = IntUiDarkTheme.colors.grey(10),
iconTintDisabled: Color = IntUiDarkTheme.colors.grey(6),
iconTintFocused: Color = iconTint,
iconTintPressed: Color = iconTint,
iconTintHovered: Color = iconTint,
- iconTintWarning: Color = iconTint,
- iconTintError: Color = iconTint,
) = IntUiDropdownColors(
background,
backgroundDisabled,
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
iconTint,
iconTintDisabled,
iconTintFocused,
iconTintPressed,
iconTintHovered,
- iconTintWarning,
- iconTintError
)
}
}
@Stable
data class IntUiDropdownMetrics(
- override val minSize: DpSize = DpSize(108.dp, 28.dp),
+ override val arrowMinSize: DpSize = DpSize((23 + 3).dp, (24 + 6).dp),
+ override val minSize: DpSize = DpSize((49 + 23 + 6).dp, (24 + 6).dp),
override val cornerSize: CornerSize = CornerSize(4.dp),
- override val contentPadding: PaddingValues = PaddingValues(start = 9.dp, end = 8.dp),
+ override val contentPadding: PaddingValues = PaddingValues(3.dp),
override val borderWidth: Dp = 1.dp,
) : DropdownMetrics
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiHorizontalProgressBarStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiHorizontalProgressBarStyling.kt
index 779eb46e736d..bb14b9f139dc 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiHorizontalProgressBarStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiHorizontalProgressBarStyling.kt
@@ -43,6 +43,7 @@ data class IntUiHorizontalProgressBarStyle(
data class IntUiHorizontalProgressBarColors(
override val track: Color,
override val progress: Color,
+ override val indeterminateBase: Color,
override val indeterminateHighlight: Color,
) : HorizontalProgressBarColors {
@@ -52,21 +53,23 @@ data class IntUiHorizontalProgressBarColors(
fun light(
track: Color = IntUiLightTheme.colors.grey(11),
progress: Color = IntUiLightTheme.colors.blue(4),
- indeterminateHighlight: Color = IntUiLightTheme.colors.grey(9),
- ) = IntUiHorizontalProgressBarColors(track, progress, indeterminateHighlight)
+ indeterminateBase: Color = IntUiLightTheme.colors.blue(9),
+ indeterminateHighlight: Color = IntUiLightTheme.colors.blue(4),
+ ) = IntUiHorizontalProgressBarColors(track, progress, indeterminateBase, indeterminateHighlight)
@Composable
fun dark(
track: Color = IntUiDarkTheme.colors.grey(4),
- progress: Color = IntUiDarkTheme.colors.blue(6),
- indeterminateHighlight: Color = IntUiDarkTheme.colors.grey(11),
- ) = IntUiHorizontalProgressBarColors(track, progress, indeterminateHighlight)
+ progress: Color = IntUiDarkTheme.colors.blue(7),
+ indeterminateBase: Color = IntUiDarkTheme.colors.blue(9),
+ indeterminateHighlight: Color = IntUiDarkTheme.colors.blue(5),
+ ) = IntUiHorizontalProgressBarColors(track, progress, indeterminateBase, indeterminateHighlight)
}
}
@Immutable
data class IntUiHorizontalProgressBarMetrics(
- override val cornerSize: CornerSize = CornerSize(2.dp),
+ override val cornerSize: CornerSize = CornerSize(100),
override val minHeight: Dp = 4.dp,
override val indeterminateHighlightWidth: Dp = 140.dp,
) : HorizontalProgressBarMetrics
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLabelledTextFieldStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLabelledTextFieldStyling.kt
index 14590700137f..c9d99c01d62e 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLabelledTextFieldStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLabelledTextFieldStyling.kt
@@ -5,9 +5,7 @@ import androidx.compose.foundation.shape.CornerSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
-import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
@@ -56,29 +54,21 @@ data class IntUiLabelledTextFieldColors(
override val backgroundFocused: Color,
override val backgroundPressed: Color,
override val backgroundHovered: Color,
- override val backgroundWarning: Color,
- override val backgroundError: Color,
override val content: Color,
override val contentDisabled: Color,
override val contentFocused: Color,
override val contentPressed: Color,
override val contentHovered: Color,
- override val contentWarning: Color,
- override val contentError: Color,
override val border: Color,
override val borderDisabled: Color,
override val borderFocused: Color,
override val borderPressed: Color,
override val borderHovered: Color,
- override val borderWarning: Color,
- override val borderError: Color,
- override val cursor: Brush,
- override val cursorDisabled: Brush,
- override val cursorFocused: Brush,
- override val cursorPressed: Brush,
- override val cursorHovered: Brush,
- override val cursorWarning: Brush,
- override val cursorError: Brush,
+ override val caret: Color,
+ override val caretDisabled: Color,
+ override val caretFocused: Color,
+ override val caretPressed: Color,
+ override val caretHovered: Color,
override val placeholder: Color,
override val label: Color,
override val hint: Color,
@@ -93,29 +83,21 @@ data class IntUiLabelledTextFieldColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiLightTheme.colors.grey(1),
contentDisabled: Color = IntUiLightTheme.colors.grey(8),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiLightTheme.colors.grey(9),
borderDisabled: Color = IntUiLightTheme.colors.grey(11),
borderFocused: Color = IntUiLightTheme.colors.blue(4),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiLightTheme.colors.yellow(4),
- borderError: Color = IntUiLightTheme.colors.red(4),
- cursor: Brush = SolidColor(IntUiLightTheme.colors.grey(1)),
- cursorDisabled: Brush = cursor,
- cursorFocused: Brush = cursor,
- cursorPressed: Brush = cursor,
- cursorHovered: Brush = cursor,
- cursorWarning: Brush = cursor,
- cursorError: Brush = cursor,
+ caret: Color = IntUiLightTheme.colors.grey(1),
+ caretDisabled: Color = caret,
+ caretFocused: Color = caret,
+ caretPressed: Color = caret,
+ caretHovered: Color = caret,
placeholder: Color = IntUiLightTheme.colors.grey(8),
label: Color = IntUiLightTheme.colors.grey(1),
hint: Color = IntUiLightTheme.colors.grey(6),
@@ -125,32 +107,24 @@ data class IntUiLabelledTextFieldColors(
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
- cursor,
- cursorDisabled,
- cursorFocused,
- cursorPressed,
- cursorHovered,
- cursorWarning,
- cursorError,
+ caret,
+ caretDisabled,
+ caretFocused,
+ caretPressed,
+ caretHovered,
placeholder,
label,
- hint
+ hint,
)
@Composable
@@ -160,29 +134,21 @@ data class IntUiLabelledTextFieldColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiDarkTheme.colors.grey(12),
contentDisabled: Color = IntUiDarkTheme.colors.grey(7),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiDarkTheme.colors.grey(5),
borderDisabled: Color = border,
borderFocused: Color = IntUiDarkTheme.colors.blue(6),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiDarkTheme.colors.yellow(4),
- borderError: Color = IntUiDarkTheme.colors.red(4),
- cursor: Brush = SolidColor(IntUiDarkTheme.colors.grey(12)),
- cursorDisabled: Brush = cursor,
- cursorFocused: Brush = cursor,
- cursorPressed: Brush = cursor,
- cursorHovered: Brush = cursor,
- cursorWarning: Brush = cursor,
- cursorError: Brush = cursor,
+ caret: Color = IntUiDarkTheme.colors.grey(12),
+ caretDisabled: Color = caret,
+ caretFocused: Color = caret,
+ caretPressed: Color = caret,
+ caretHovered: Color = caret,
placeholder: Color = IntUiDarkTheme.colors.grey(7),
label: Color = IntUiDarkTheme.colors.grey(12),
hint: Color = IntUiDarkTheme.colors.grey(7),
@@ -192,32 +158,24 @@ data class IntUiLabelledTextFieldColors(
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
- cursor,
- cursorDisabled,
- cursorFocused,
- cursorPressed,
- cursorHovered,
- cursorWarning,
- cursorError,
+ caret,
+ caretDisabled,
+ caretFocused,
+ caretPressed,
+ caretHovered,
placeholder,
label,
- hint
+ hint,
)
}
}
@@ -225,8 +183,8 @@ data class IntUiLabelledTextFieldColors(
@Stable
data class IntUiLabelledTextFieldMetrics(
override val cornerSize: CornerSize = CornerSize(4.dp),
- override val contentPadding: PaddingValues = PaddingValues(horizontal = 6.dp, vertical = 9.dp),
- override val minSize: DpSize = DpSize(144.dp, 28.dp),
+ override val contentPadding: PaddingValues = PaddingValues(horizontal = 9.dp, vertical = 6.dp),
+ override val minSize: DpSize = DpSize(49.dp, 24.dp),
override val borderWidth: Dp = 1.dp,
override val labelSpacing: Dp = 6.dp,
override val hintSpacing: Dp = 6.dp,
@@ -245,7 +203,7 @@ data class IntUiLabelledTextFieldTextStyles(
label: TextStyle = IntUiTheme.defaultLightTextStyle,
hint: TextStyle = IntUiTheme.defaultLightTextStyle.copy(
fontSize = 12.sp,
- lineHeight = 16.sp
+ lineHeight = 16.sp,
),
) = IntUiLabelledTextFieldTextStyles(label, hint)
@@ -254,7 +212,7 @@ data class IntUiLabelledTextFieldTextStyles(
label: TextStyle = IntUiTheme.defaultDarkTextStyle,
hint: TextStyle = IntUiTheme.defaultDarkTextStyle.copy(
fontSize = 12.sp,
- lineHeight = 16.sp
+ lineHeight = 16.sp,
),
) = IntUiLabelledTextFieldTextStyles(label, hint)
}
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLazyTreeStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLazyTreeStyling.kt
index 2e193b137b00..df11cec92675 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLazyTreeStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLazyTreeStyling.kt
@@ -8,10 +8,14 @@ import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import org.jetbrains.jewel.SvgLoader
+import org.jetbrains.jewel.foundation.tree.TreeElementState
import org.jetbrains.jewel.styling.LazyTreeColors
import org.jetbrains.jewel.styling.LazyTreeIcons
import org.jetbrains.jewel.styling.LazyTreeMetrics
import org.jetbrains.jewel.styling.LazyTreeStyle
+import org.jetbrains.jewel.styling.ResourcePainterProvider
+import org.jetbrains.jewel.styling.StatefulPainterProvider
import org.jetbrains.jewel.themes.intui.core.theme.IntUiDarkTheme
import org.jetbrains.jewel.themes.intui.core.theme.IntUiLightTheme
@@ -26,16 +30,18 @@ data class IntUiLazyTreeStyle(
@Composable
fun light(
+ svgLoader: SvgLoader,
colors: IntUiLazyTreeColors = IntUiLazyTreeColors.light(),
metrics: IntUiLazyTreeMetrics = IntUiLazyTreeMetrics(),
- icons: IntUiLazyTreeIcons = IntUiLazyTreeIcons(),
+ icons: IntUiLazyTreeIcons = intUiLazyTreeIcons(svgLoader),
) = IntUiLazyTreeStyle(colors, metrics, icons)
@Composable
fun dark(
+ svgLoader: SvgLoader,
colors: IntUiLazyTreeColors = IntUiLazyTreeColors.dark(),
metrics: IntUiLazyTreeMetrics = IntUiLazyTreeMetrics(),
- icons: IntUiLazyTreeIcons = IntUiLazyTreeIcons(),
+ icons: IntUiLazyTreeIcons = intUiLazyTreeIcons(svgLoader),
) = IntUiLazyTreeStyle(colors, metrics, icons)
}
}
@@ -49,10 +55,6 @@ data class IntUiLazyTreeColors(
override val elementBackgroundFocused: Color,
override val elementBackgroundSelected: Color,
override val elementBackgroundSelectedFocused: Color,
- override val chevronTint: Color,
- override val chevronTintSelected: Color,
- override val chevronTintFocused: Color,
- override val chevronTintSelectedFocused: Color,
) : LazyTreeColors {
companion object {
@@ -66,10 +68,6 @@ data class IntUiLazyTreeColors(
nodeBackgroundFocused: Color = Color.Unspecified,
nodeBackgroundSelected: Color = IntUiLightTheme.colors.grey(11),
nodeBackgroundSelectedFocused: Color = IntUiLightTheme.colors.blue(11),
- chevronTint: Color = IntUiLightTheme.colors.grey(7),
- chevronTintSelected: Color = chevronTint,
- chevronTintFocused: Color = chevronTint,
- chevronTintSelectedFocused: Color = chevronTint,
) = IntUiLazyTreeColors(
content,
contentFocused,
@@ -78,10 +76,6 @@ data class IntUiLazyTreeColors(
nodeBackgroundFocused,
nodeBackgroundSelected,
nodeBackgroundSelectedFocused,
- chevronTint,
- chevronTintSelected,
- chevronTintFocused,
- chevronTintSelectedFocused
)
@Composable
@@ -93,10 +87,6 @@ data class IntUiLazyTreeColors(
nodeBackgroundFocused: Color = Color.Unspecified,
nodeBackgroundSelected: Color = IntUiDarkTheme.colors.grey(4),
nodeBackgroundSelectedFocused: Color = IntUiDarkTheme.colors.blue(2),
- chevronTint: Color = IntUiDarkTheme.colors.grey(10),
- chevronTintSelected: Color = chevronTint,
- chevronTintFocused: Color = chevronTint,
- chevronTintSelectedFocused: Color = chevronTint,
) = IntUiLazyTreeColors(
content,
contentFocused,
@@ -105,17 +95,13 @@ data class IntUiLazyTreeColors(
nodeBackgroundFocused,
nodeBackgroundSelected,
nodeBackgroundSelectedFocused,
- chevronTint,
- chevronTintSelected,
- chevronTintFocused,
- chevronTintSelectedFocused
)
}
}
@Stable
data class IntUiLazyTreeMetrics(
- override val indentSize: Dp = 8.dp + 16.dp,
+ override val indentSize: Dp = 7.dp + 16.dp,
override val elementBackgroundCornerSize: CornerSize = CornerSize(4.dp),
override val elementPadding: PaddingValues = PaddingValues(horizontal = 12.dp),
override val elementContentPadding: PaddingValues = PaddingValues(4.dp),
@@ -125,5 +111,33 @@ data class IntUiLazyTreeMetrics(
@Immutable
data class IntUiLazyTreeIcons(
- override val nodeChevron: String = "icons/intui/chevronRight.svg",
-) : LazyTreeIcons
+ override val nodeChevronCollapsed: StatefulPainterProvider,
+ override val nodeChevronExpanded: StatefulPainterProvider,
+) : LazyTreeIcons {
+
+ companion object {
+
+ @Composable
+ fun nodeChevronCollapsed(
+ svgLoader: SvgLoader,
+ basePath: String = "icons/intui/chevronRight.svg",
+ ): StatefulPainterProvider =
+ ResourcePainterProvider(basePath, svgLoader)
+
+ @Composable
+ fun nodeChevronExpanded(
+ svgLoader: SvgLoader,
+ basePath: String = "icons/intui/chevronDown.svg",
+ ): StatefulPainterProvider =
+ ResourcePainterProvider(basePath, svgLoader)
+ }
+}
+
+@Composable
+fun intUiLazyTreeIcons(
+ svgLoader: SvgLoader,
+ nodeChevronCollapsed: StatefulPainterProvider =
+ IntUiLazyTreeIcons.nodeChevronCollapsed(svgLoader),
+ nodeChevronExpanded: StatefulPainterProvider =
+ IntUiLazyTreeIcons.nodeChevronExpanded(svgLoader),
+) = IntUiLazyTreeIcons(nodeChevronCollapsed, nodeChevronExpanded)
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLinkStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLinkStyling.kt
index f4712d3334d1..0e3d35e738ec 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLinkStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiLinkStyling.kt
@@ -60,8 +60,6 @@ data class IntUiLinkColors(
override val contentPressed: Color,
override val contentHovered: Color,
override val contentVisited: Color,
- override val iconTint: Color,
- override val iconTintDisabled: Color,
) : LinkColors {
companion object {
@@ -74,8 +72,6 @@ data class IntUiLinkColors(
contentPressed: Color = content,
contentHovered: Color = content,
contentVisited: Color = content,
- iconTint: Color = Color.Unspecified,
- iconTintDisabled: Color = IntUiLightTheme.colors.grey(9),
) = IntUiLinkColors(
content,
contentDisabled,
@@ -83,8 +79,6 @@ data class IntUiLinkColors(
contentPressed,
contentHovered,
contentVisited,
- iconTint,
- iconTintDisabled
)
@Composable
@@ -95,8 +89,6 @@ data class IntUiLinkColors(
contentPressed: Color = content,
contentHovered: Color = content,
contentVisited: Color = content,
- iconTint: Color = Color.Unspecified,
- iconTintDisabled: Color = IntUiDarkTheme.colors.grey(6),
) = IntUiLinkColors(
content,
contentDisabled,
@@ -104,8 +96,6 @@ data class IntUiLinkColors(
contentPressed,
contentHovered,
contentVisited,
- iconTint,
- iconTintDisabled
)
}
}
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiMenuStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiMenuStyling.kt
index df09e89f44b2..642cdbf2e995 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiMenuStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiMenuStyling.kt
@@ -5,18 +5,20 @@ import androidx.compose.foundation.shape.CornerSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
-import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
+import org.jetbrains.jewel.MenuItemState
+import org.jetbrains.jewel.SvgLoader
import org.jetbrains.jewel.styling.MenuColors
import org.jetbrains.jewel.styling.MenuIcons
import org.jetbrains.jewel.styling.MenuItemColors
import org.jetbrains.jewel.styling.MenuItemMetrics
import org.jetbrains.jewel.styling.MenuMetrics
import org.jetbrains.jewel.styling.MenuStyle
+import org.jetbrains.jewel.styling.ResourcePainterProvider
+import org.jetbrains.jewel.styling.StatefulPainterProvider
import org.jetbrains.jewel.styling.SubmenuMetrics
import org.jetbrains.jewel.themes.intui.core.theme.IntUiDarkTheme
import org.jetbrains.jewel.themes.intui.core.theme.IntUiLightTheme
@@ -32,23 +34,25 @@ data class IntUiMenuStyle(
@Composable
fun light(
+ svgLoader: SvgLoader,
colors: IntUiMenuColors = IntUiMenuColors.light(),
metrics: IntUiMenuMetrics = IntUiMenuMetrics(),
- icons: IntUiMenuIcons = IntUiMenuIcons(),
+ icons: IntUiMenuIcons = intUiMenuIcons(svgLoader),
) = IntUiMenuStyle(colors, metrics, icons)
@Composable
fun dark(
+ svgLoader: SvgLoader,
colors: IntUiMenuColors = IntUiMenuColors.dark(),
metrics: IntUiMenuMetrics = IntUiMenuMetrics(),
- icons: IntUiMenuIcons = IntUiMenuIcons(),
+ icons: IntUiMenuIcons = intUiMenuIcons(svgLoader),
) = IntUiMenuStyle(colors, metrics, icons)
}
}
@Immutable
data class IntUiMenuColors(
- override val background: Brush,
+ override val background: Color,
override val border: Color,
override val shadow: Color,
override val itemColors: IntUiMenuItemColors,
@@ -58,7 +62,7 @@ data class IntUiMenuColors(
@Composable
fun light(
- background: Brush = SolidColor(IntUiLightTheme.colors.grey(14)),
+ background: Color = IntUiLightTheme.colors.grey(14),
border: Color = IntUiLightTheme.colors.grey(9),
shadow: Color = Color(0x78919191), // Not a palette color
itemColors: IntUiMenuItemColors = IntUiMenuItemColors.light(),
@@ -66,7 +70,7 @@ data class IntUiMenuColors(
@Composable
fun dark(
- background: Brush = SolidColor(IntUiDarkTheme.colors.grey(2)),
+ background: Color = IntUiDarkTheme.colors.grey(2),
border: Color = IntUiDarkTheme.colors.grey(3),
shadow: Color = Color(0x66000000), // Not a palette color
itemColors: IntUiMenuItemColors = IntUiMenuItemColors.dark(),
@@ -130,7 +134,7 @@ data class IntUiMenuItemColors(
iconTintFocused,
iconTintPressed,
iconTintHovered,
- separator
+ separator,
)
@Composable
@@ -167,7 +171,7 @@ data class IntUiMenuItemColors(
iconTintFocused,
iconTintPressed,
iconTintHovered,
- separator
+ separator,
)
}
}
@@ -175,8 +179,7 @@ data class IntUiMenuItemColors(
@Stable
data class IntUiMenuMetrics(
override val cornerSize: CornerSize = CornerSize(8.dp),
- override val margin: PaddingValues = PaddingValues(8.dp),
- override val padding: PaddingValues = PaddingValues(12.dp),
+ override val menuMargin: PaddingValues = PaddingValues(vertical = 6.dp),
override val contentPadding: PaddingValues = PaddingValues(vertical = 8.dp),
override val offset: DpOffset = DpOffset(0.dp, 2.dp),
override val shadowSize: Dp = 12.dp,
@@ -187,19 +190,37 @@ data class IntUiMenuMetrics(
@Stable
data class IntUiMenuItemMetrics(
- override val cornerSize: CornerSize = CornerSize(8.dp),
- override val padding: PaddingValues = PaddingValues(horizontal = 12.dp),
- override val contentPadding: PaddingValues = PaddingValues(horizontal = 8.dp, vertical = 4.dp),
+ override val selectionCornerSize: CornerSize = CornerSize(4.dp),
+ override val outerPadding: PaddingValues = PaddingValues(horizontal = 4.dp),
+ override val contentPadding: PaddingValues = PaddingValues(horizontal = 12.dp, vertical = 4.dp),
override val separatorPadding: PaddingValues = PaddingValues(horizontal = 12.dp, vertical = 4.dp),
+ override val separatorThickness: Dp = 1.dp,
) : MenuItemMetrics
@Stable
data class IntUiSubmenuMetrics(
- override val offset: DpOffset = DpOffset(2.dp, (-8).dp),
- override val itemPadding: PaddingValues = PaddingValues(start = 8.dp, top = 4.dp, bottom = 4.dp),
+ override val offset: DpOffset = DpOffset(0.dp, (-8).dp),
) : SubmenuMetrics
@Immutable
data class IntUiMenuIcons(
- override val submenuChevron: String = "icons/intui/chevronRight.svg",
-) : MenuIcons
+ override val submenuChevron: StatefulPainterProvider,
+) : MenuIcons {
+
+ companion object {
+
+ @Composable
+ fun submenuChevron(
+ svgLoader: SvgLoader,
+ basePath: String = "icons/intui/chevronRight.svg",
+ ): StatefulPainterProvider =
+ ResourcePainterProvider(basePath, svgLoader)
+ }
+}
+
+@Composable
+fun intUiMenuIcons(
+ svgLoader: SvgLoader,
+ submenuChevron: StatefulPainterProvider = IntUiMenuIcons.submenuChevron(svgLoader),
+) =
+ IntUiMenuIcons(submenuChevron)
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiRadioButtonStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiRadioButtonStyling.kt
index 895e2f5140c7..e73a2df67d08 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiRadioButtonStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiRadioButtonStyling.kt
@@ -8,7 +8,6 @@ import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import org.jetbrains.jewel.RadioButtonState
import org.jetbrains.jewel.SvgLoader
-import org.jetbrains.jewel.styling.RadioButtonButtonColors
import org.jetbrains.jewel.styling.RadioButtonColors
import org.jetbrains.jewel.styling.RadioButtonIcons
import org.jetbrains.jewel.styling.RadioButtonMetrics
@@ -54,7 +53,6 @@ data class IntUiRadioButtonColors(
override val contentSelected: Color,
override val contentSelectedHovered: Color,
override val contentSelectedDisabled: Color,
- override val buttonColors: IntUiRadioButtonButtonColors,
) : RadioButtonColors {
companion object {
@@ -67,7 +65,6 @@ data class IntUiRadioButtonColors(
contentSelected: Color = content,
contentSelectedHovered: Color = content,
contentSelectedDisabled: Color = content,
- buttonColors: IntUiRadioButtonButtonColors = IntUiRadioButtonButtonColors.light(),
) = IntUiRadioButtonColors(
content,
contentHovered,
@@ -75,7 +72,6 @@ data class IntUiRadioButtonColors(
contentSelected,
contentSelectedHovered,
contentSelectedDisabled,
- buttonColors
)
@Composable
@@ -86,7 +82,6 @@ data class IntUiRadioButtonColors(
contentSelected: Color = content,
contentSelectedHovered: Color = content,
contentSelectedDisabled: Color = content,
- buttonColors: IntUiRadioButtonButtonColors = IntUiRadioButtonButtonColors.dark(),
) = IntUiRadioButtonColors(
content,
contentHovered,
@@ -94,107 +89,13 @@ data class IntUiRadioButtonColors(
contentSelected,
contentSelectedHovered,
contentSelectedDisabled,
- buttonColors
- )
- }
-}
-
-@Immutable
-data class IntUiRadioButtonButtonColors(
- override val fill: Color,
- override val fillHovered: Color,
- override val fillDisabled: Color,
- override val fillSelected: Color,
- override val fillSelectedHovered: Color,
- override val fillSelectedDisabled: Color,
- override val border: Color,
- override val borderHovered: Color,
- override val borderDisabled: Color,
- override val borderSelected: Color,
- override val borderSelectedHovered: Color,
- override val borderSelectedDisabled: Color,
- override val markSelected: Color,
- override val markSelectedHovered: Color,
- override val markSelectedDisabled: Color,
-) : RadioButtonButtonColors {
-
- companion object {
-
- @Composable
- fun light(
- fill: Color = IntUiLightTheme.colors.grey(14),
- fillHovered: Color = fill,
- fillDisabled: Color = IntUiLightTheme.colors.grey(13),
- fillSelected: Color = IntUiLightTheme.colors.blue(4),
- fillSelectedHovered: Color = IntUiLightTheme.colors.blue(3),
- fillSelectedDisabled: Color = fillDisabled,
- border: Color = IntUiLightTheme.colors.grey(8),
- borderHovered: Color = IntUiLightTheme.colors.grey(6),
- borderDisabled: Color = IntUiLightTheme.colors.grey(11),
- borderSelected: Color = Color.Unspecified,
- borderSelectedHovered: Color = borderSelected,
- borderSelectedDisabled: Color = borderDisabled,
- markSelected: Color = IntUiLightTheme.colors.grey(14),
- markSelectedHovered: Color = markSelected,
- markSelectedDisabled: Color = IntUiLightTheme.colors.grey(9),
- ) = IntUiRadioButtonButtonColors(
- fill,
- fillHovered,
- fillDisabled,
- fillSelected,
- fillSelectedHovered,
- fillSelectedDisabled,
- border,
- borderHovered,
- borderDisabled,
- borderSelected,
- borderSelectedHovered,
- borderSelectedDisabled,
- markSelected,
- markSelectedHovered,
- markSelectedDisabled
- )
-
- @Composable
- fun dark(
- fill: Color = Color.Unspecified,
- fillHovered: Color = fill,
- fillDisabled: Color = IntUiDarkTheme.colors.grey(3),
- fillSelected: Color = IntUiDarkTheme.colors.blue(6),
- fillSelectedHovered: Color = IntUiDarkTheme.colors.blue(5),
- fillSelectedDisabled: Color = fillDisabled,
- border: Color = IntUiDarkTheme.colors.grey(6),
- borderHovered: Color = IntUiDarkTheme.colors.grey(9),
- borderDisabled: Color = IntUiDarkTheme.colors.grey(6),
- borderSelected: Color = Color.Unspecified,
- borderSelectedHovered: Color = borderSelected,
- borderSelectedDisabled: Color = borderDisabled,
- markSelected: Color = IntUiDarkTheme.colors.grey(14),
- markSelectedHovered: Color = markSelected,
- markSelectedDisabled: Color = IntUiDarkTheme.colors.grey(7),
- ) = IntUiRadioButtonButtonColors(
- fill,
- fillHovered,
- fillDisabled,
- fillSelected,
- fillSelectedHovered,
- fillSelectedDisabled,
- border,
- borderHovered,
- borderDisabled,
- borderSelected,
- borderSelectedHovered,
- borderSelectedDisabled,
- markSelected,
- markSelectedHovered,
- markSelectedDisabled
)
}
}
@Immutable
data class IntUiRadioButtonMetrics(
- override val radioButtonSize: DpSize = DpSize(16.dp, 16.dp),
+ override val radioButtonSize: DpSize = DpSize(19.dp, 19.dp),
override val iconContentGap: Dp = 8.dp,
) : RadioButtonMetrics
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiScrollbarStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiScrollbarStyling.kt
index 77dc2bbd1db3..48df91e6b724 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiScrollbarStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiScrollbarStyling.kt
@@ -66,5 +66,5 @@ data class IntUiScrollbarMetrics(
override val thumbCornerSize: CornerSize = CornerSize(100),
override val thumbThickness: Dp = 8.dp,
override val minThumbLength: Dp = 16.dp,
- override val trackPadding: PaddingValues = PaddingValues(4.dp),
+ override val trackPadding: PaddingValues = PaddingValues(start = 7.dp, end = 3.dp),
) : ScrollbarMetrics
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTabStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTabStyling.kt
index 7fe25b6b7cb3..f2aa39f08fde 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTabStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTabStyling.kt
@@ -158,7 +158,7 @@ data class IntUiTabColors(
underlineFocused,
underlinePressed,
underlineHovered,
- underlineSelected
+ underlineSelected,
)
fun dark(
@@ -198,7 +198,7 @@ data class IntUiTabColors(
underlineFocused,
underlinePressed,
underlineHovered,
- underlineSelected
+ underlineSelected,
)
}
@@ -241,7 +241,7 @@ data class IntUiTabColors(
underlineFocused,
underlinePressed,
underlineHovered,
- underlineSelected
+ underlineSelected,
)
fun dark(
@@ -283,7 +283,7 @@ data class IntUiTabColors(
underlineFocused,
underlinePressed,
underlineHovered,
- underlineSelected
+ underlineSelected,
)
}
}
@@ -331,7 +331,7 @@ data class IntUiTabContentAlpha(
labelFocused,
labelPressed,
labelHovered,
- labelSelected
+ labelSelected,
)
fun editor(
@@ -360,7 +360,7 @@ data class IntUiTabContentAlpha(
labelFocused,
labelPressed,
labelHovered,
- labelSelected
+ labelSelected,
)
}
}
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextAreaStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextAreaStyling.kt
index 40ce00787fd1..700cf987460a 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextAreaStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextAreaStyling.kt
@@ -5,14 +5,11 @@ import androidx.compose.foundation.shape.CornerSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
-import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
import org.jetbrains.jewel.styling.InputFieldMetrics
import org.jetbrains.jewel.styling.TextAreaColors
import org.jetbrains.jewel.styling.TextAreaStyle
@@ -25,7 +22,6 @@ data class IntUiTextAreaStyle(
override val colors: IntUiTextAreaColors,
override val metrics: IntUiTextAreaMetrics,
override val textStyle: TextStyle,
- override val hintTextStyle: TextStyle,
) : TextAreaStyle {
companion object {
@@ -35,16 +31,14 @@ data class IntUiTextAreaStyle(
colors: IntUiTextAreaColors = IntUiTextAreaColors.light(),
metrics: IntUiTextAreaMetrics = IntUiTextAreaMetrics(),
textStyle: TextStyle = IntUiTheme.defaultLightTextStyle,
- hintTextStyle: TextStyle = IntUiTheme.defaultLightTextStyle.copy(fontSize = 12.sp, lineHeight = 16.sp),
- ) = IntUiTextAreaStyle(colors, metrics, textStyle, hintTextStyle)
+ ) = IntUiTextAreaStyle(colors, metrics, textStyle)
@Composable
fun dark(
colors: IntUiTextAreaColors = IntUiTextAreaColors.dark(),
metrics: IntUiTextAreaMetrics = IntUiTextAreaMetrics(),
textStyle: TextStyle = IntUiTheme.defaultDarkTextStyle,
- hintTextStyle: TextStyle = IntUiTheme.defaultDarkTextStyle.copy(fontSize = 12.sp, lineHeight = 16.sp),
- ) = IntUiTextAreaStyle(colors, metrics, textStyle, hintTextStyle)
+ ) = IntUiTextAreaStyle(colors, metrics, textStyle)
}
}
@@ -55,32 +49,22 @@ data class IntUiTextAreaColors(
override val backgroundFocused: Color,
override val backgroundPressed: Color,
override val backgroundHovered: Color,
- override val backgroundWarning: Color,
- override val backgroundError: Color,
override val content: Color,
override val contentDisabled: Color,
override val contentFocused: Color,
override val contentPressed: Color,
override val contentHovered: Color,
- override val contentWarning: Color,
- override val contentError: Color,
override val border: Color,
override val borderDisabled: Color,
override val borderFocused: Color,
override val borderPressed: Color,
override val borderHovered: Color,
- override val borderWarning: Color,
- override val borderError: Color,
- override val cursor: Brush,
- override val cursorDisabled: Brush,
- override val cursorFocused: Brush,
- override val cursorPressed: Brush,
- override val cursorHovered: Brush,
- override val cursorWarning: Brush,
- override val cursorError: Brush,
+ override val caret: Color,
+ override val caretDisabled: Color,
+ override val caretFocused: Color,
+ override val caretPressed: Color,
+ override val caretHovered: Color,
override val placeholder: Color,
- override val hintContent: Color,
- override val hintContentDisabled: Color,
) : TextAreaColors {
companion object {
@@ -92,64 +76,44 @@ data class IntUiTextAreaColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiLightTheme.colors.grey(1),
contentDisabled: Color = IntUiLightTheme.colors.grey(8),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiLightTheme.colors.grey(9),
borderDisabled: Color = IntUiLightTheme.colors.grey(11),
borderFocused: Color = IntUiLightTheme.colors.blue(4),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiLightTheme.colors.yellow(4),
- borderError: Color = IntUiLightTheme.colors.red(4),
- cursor: Brush = SolidColor(IntUiLightTheme.colors.grey(1)),
- cursorDisabled: Brush = cursor,
- cursorFocused: Brush = cursor,
- cursorPressed: Brush = cursor,
- cursorHovered: Brush = cursor,
- cursorWarning: Brush = cursor,
- cursorError: Brush = cursor,
+ caret: Color = IntUiLightTheme.colors.grey(1),
+ caretDisabled: Color = caret,
+ caretFocused: Color = caret,
+ caretPressed: Color = caret,
+ caretHovered: Color = caret,
placeholder: Color = IntUiLightTheme.colors.grey(8),
- hintContent: Color = IntUiLightTheme.colors.grey(7),
- hintContentDisabled: Color = hintContent,
) = IntUiTextAreaColors(
background,
backgroundDisabled,
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
- cursor,
- cursorDisabled,
- cursorFocused,
- cursorPressed,
- cursorHovered,
- cursorWarning,
- cursorError,
+ caret,
+ caretDisabled,
+ caretFocused,
+ caretPressed,
+ caretHovered,
placeholder,
- hintContent,
- hintContentDisabled
)
@Composable
@@ -159,64 +123,44 @@ data class IntUiTextAreaColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiDarkTheme.colors.grey(12),
contentDisabled: Color = IntUiDarkTheme.colors.grey(7),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiDarkTheme.colors.grey(5),
borderDisabled: Color = border,
borderFocused: Color = IntUiDarkTheme.colors.blue(6),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiDarkTheme.colors.yellow(4),
- borderError: Color = IntUiDarkTheme.colors.red(4),
- cursor: Brush = SolidColor(IntUiDarkTheme.colors.grey(12)),
- cursorDisabled: Brush = cursor,
- cursorFocused: Brush = cursor,
- cursorPressed: Brush = cursor,
- cursorHovered: Brush = cursor,
- cursorWarning: Brush = cursor,
- cursorError: Brush = cursor,
+ caret: Color = IntUiDarkTheme.colors.grey(12),
+ caretDisabled: Color = caret,
+ caretFocused: Color = caret,
+ caretPressed: Color = caret,
+ caretHovered: Color = caret,
placeholder: Color = IntUiDarkTheme.colors.grey(7),
- hintContent: Color = IntUiDarkTheme.colors.grey(8),
- hintContentDisabled: Color = hintContent,
) = IntUiTextAreaColors(
background,
backgroundDisabled,
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
- cursor,
- cursorDisabled,
- cursorFocused,
- cursorPressed,
- cursorHovered,
- cursorWarning,
- cursorError,
+ caret,
+ caretDisabled,
+ caretFocused,
+ caretPressed,
+ caretHovered,
placeholder,
- hintContent,
- hintContentDisabled
)
}
}
@@ -224,7 +168,7 @@ data class IntUiTextAreaColors(
@Stable
data class IntUiTextAreaMetrics(
override val cornerSize: CornerSize = CornerSize(4.dp),
- override val contentPadding: PaddingValues = PaddingValues(horizontal = 6.dp, vertical = 9.dp),
+ override val contentPadding: PaddingValues = PaddingValues(horizontal = 6.dp, vertical = 2.dp),
override val minSize: DpSize = DpSize(144.dp, 28.dp),
override val borderWidth: Dp = 1.dp,
) : InputFieldMetrics
diff --git a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextFieldStyling.kt b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextFieldStyling.kt
index 5eb48d75e090..8992fb51528b 100644
--- a/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextFieldStyling.kt
+++ b/platform/jewel/themes/int-ui/int-ui-standalone/src/main/kotlin/org/jetbrains/jewel/themes/intui/standalone/styling/IntUiTextFieldStyling.kt
@@ -5,9 +5,7 @@ import androidx.compose.foundation.shape.CornerSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
-import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
@@ -51,29 +49,21 @@ data class IntUiTextFieldColors(
override val backgroundFocused: Color,
override val backgroundPressed: Color,
override val backgroundHovered: Color,
- override val backgroundWarning: Color,
- override val backgroundError: Color,
override val content: Color,
override val contentDisabled: Color,
override val contentFocused: Color,
override val contentPressed: Color,
override val contentHovered: Color,
- override val contentWarning: Color,
- override val contentError: Color,
override val border: Color,
override val borderDisabled: Color,
override val borderFocused: Color,
override val borderPressed: Color,
override val borderHovered: Color,
- override val borderWarning: Color,
- override val borderError: Color,
- override val cursor: Brush,
- override val cursorDisabled: Brush,
- override val cursorFocused: Brush,
- override val cursorPressed: Brush,
- override val cursorHovered: Brush,
- override val cursorWarning: Brush,
- override val cursorError: Brush,
+ override val caret: Color,
+ override val caretDisabled: Color,
+ override val caretFocused: Color,
+ override val caretPressed: Color,
+ override val caretHovered: Color,
override val placeholder: Color,
) : TextFieldColors {
@@ -86,29 +76,21 @@ data class IntUiTextFieldColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiLightTheme.colors.grey(1),
contentDisabled: Color = IntUiLightTheme.colors.grey(8),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiLightTheme.colors.grey(9),
borderDisabled: Color = IntUiLightTheme.colors.grey(11),
borderFocused: Color = IntUiLightTheme.colors.blue(4),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiLightTheme.colors.yellow(4),
- borderError: Color = IntUiLightTheme.colors.red(4),
- cursor: Brush = SolidColor(IntUiLightTheme.colors.grey(1)),
- cursorDisabled: Brush = cursor,
- cursorFocused: Brush = cursor,
- cursorPressed: Brush = cursor,
- cursorHovered: Brush = cursor,
- cursorWarning: Brush = cursor,
- cursorError: Brush = cursor,
+ caret: Color = IntUiLightTheme.colors.grey(1),
+ caretDisabled: Color = caret,
+ caretFocused: Color = caret,
+ caretPressed: Color = caret,
+ caretHovered: Color = caret,
placeholder: Color = IntUiLightTheme.colors.grey(8),
) = IntUiTextFieldColors(
background,
@@ -116,30 +98,22 @@ data class IntUiTextFieldColors(
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
- cursor,
- cursorDisabled,
- cursorFocused,
- cursorPressed,
- cursorHovered,
- cursorWarning,
- cursorError,
- placeholder
+ caret,
+ caretDisabled,
+ caretFocused,
+ caretPressed,
+ caretHovered,
+ placeholder,
)
@Composable
@@ -149,29 +123,21 @@ data class IntUiTextFieldColors(
backgroundFocused: Color = background,
backgroundPressed: Color = background,
backgroundHovered: Color = background,
- backgroundWarning: Color = background,
- backgroundError: Color = background,
content: Color = IntUiDarkTheme.colors.grey(12),
contentDisabled: Color = IntUiDarkTheme.colors.grey(7),
contentFocused: Color = content,
contentPressed: Color = content,
contentHovered: Color = content,
- contentWarning: Color = content,
- contentError: Color = content,
border: Color = IntUiDarkTheme.colors.grey(5),
borderDisabled: Color = border,
borderFocused: Color = IntUiDarkTheme.colors.blue(6),
borderPressed: Color = border,
borderHovered: Color = border,
- borderWarning: Color = IntUiDarkTheme.colors.yellow(4),
- borderError: Color = IntUiDarkTheme.colors.red(4),
- cursor: Brush = SolidColor(IntUiDarkTheme.colors.grey(12)),
- cursorDisabled: Brush = cursor,
- cursorFocused: Brush = cursor,
- cursorPressed: Brush = cursor,
- cursorHovered: Brush = cursor,
- cursorWarning: Brush = cursor,
- cursorError: Brush = cursor,
+ caret: Color = IntUiDarkTheme.colors.grey(12),
+ caretDisabled: Color = caret,
+ caretFocused: Color = caret,
+ caretPressed: Color = caret,
+ caretHovered: Color = caret,
placeholder: Color = IntUiDarkTheme.colors.grey(7),
) = IntUiTextFieldColors(
background,
@@ -179,30 +145,22 @@ data class IntUiTextFieldColors(
backgroundFocused,
backgroundPressed,
backgroundHovered,
- backgroundWarning,
- backgroundError,
content,
contentDisabled,
contentFocused,
contentPressed,
contentHovered,
- contentWarning,
- contentError,
border,
borderDisabled,
borderFocused,
borderPressed,
borderHovered,
- borderWarning,
- borderError,
- cursor,
- cursorDisabled,
- cursorFocused,
- cursorPressed,
- cursorHovered,
- cursorWarning,
- cursorError,
- placeholder
+ caret,
+ caretDisabled,
+ caretFocused,
+ caretPressed,
+ caretHovered,
+ placeholder,
)
}
}
@@ -210,7 +168,7 @@ data class IntUiTextFieldColors(
@Stable
data class IntUiTextFieldMetrics(
override val cornerSize: CornerSize = CornerSize(4.dp),
- override val contentPadding: PaddingValues = PaddingValues(horizontal = 6.dp, vertical = 9.dp),
+ override val contentPadding: PaddingValues = PaddingValues(horizontal = 9.dp, vertical = 6.dp),
override val minSize: DpSize = DpSize(144.dp, 28.dp),
override val borderWidth: Dp = 1.dp,
) : InputFieldMetrics