Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Housekeeping #121

Merged
merged 4 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 46 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,77 +4,67 @@

<img alt="Jewel logo" src="art/jewel-logo.svg" width="20%"/>

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 IntelliJ Platform's _New UI_ Swing Look and Feel in Compose for Desktop, providing a
desktop-optimized theme and set of components.

> **Warning**
> [!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.
> you should expect APIs to change fairly often, things to move around and/or break, and all that jazz.
>
> Use at your risk!

Jewel provides stand-alone implementations of the IntelliJ Platform themes that can be used in any Compose for Desktop
application, and a Swing LaF Bridge that only works in the IntelliJ Platform (i.e., used to create IDE plugins), but
automatically mirrors the current Swing LaF into Compose for a native-looking, consistent UI.

## Project structure

The project is split in modules:

1. `core` is the base Jewel library code (composables, interface definitions, etc.)
2. `compose-utils` is a collection of utilities for dealing with Compose, and Swing interop
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
bridge (more
on that later)
2. `new-ui` implements the new IntelliJ LaF, known as "new UI". This also has the same two implementations
4. `samples` contains the example apps, which showcase the available components:
1. `buildSrc` contains the build logic, including:
* The `jewel` and `jewel-publish` configuration plugins
* The Theme Palette generator plugin
2. `core` contains the foundational Jewel functionality, including the components and their styling primitives
3. `int-ui` implements the standalone version of the IntelliJ New UI, which implements the
["Int UI" design system](https://www.figma.com/community/file/1227732692272811382/int-ui-kit), and can be used
anywhere
4. `ide-laf-bridge` contains the Swing LaF bridge to use in IntelliJ Platform plugins (see more below)
5. `samples` contains the example apps, which showcase the available components:
1. `standalone` is a regular CfD app, using the predefined "base" theme definitions
2. `ide-plugin` is an IntelliJ plugin, adding some UI to the IDE, and showcasing the use of the bridge (see later)

### Running the samples
2. `ide-plugin` is an IntelliJ plugin, adding some UI to the IDE, and showcasing the use of the Swing Bridge

To run the stand-alone sample app, you can run the `:samples:standalone:run` Gradle task.
### Int UI Standalone theme

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).
The standalone theme can be used in any Compose for Desktop app. You use it as a normal theme, and you can customise it
to your heart's content. By default, it matches the official Int UI specs.

If you're using IntelliJ IDEA, you can use the "Stand-alone sample" and "IDE sample" run configurations.
> [!WARNING]
> Note that Jewel **requires** the JetBrains Runtime to work correctly. Some features like font loading depend on it,
> as it has extra features and patches for UI functionalities that aren't available in other JDKs.
> We **do not support** running Jewel on any other JDK.

### 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
world.
Jewel includes a crucial element for proper integration with the IDE: a bridge between the Swing components, 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
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
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
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
the bridge.

To see debug logs in the IDE, add these to __Help | Diagnostic Tools | Debug Log Settings__:
theme, and apply them to the Compose components as well — at least for themes that use the
standard [IntelliJ theming](https://plugins.jetbrains.com/docs/intellij/themes-getting-started.html) mechanisms.

```
#org.jetbrains.jewel.demo
#org.jetbrains.jewel
> [!NOTE]
> IntelliJ themes that use non-standard mechanisms (such as providing custom UI implementations for Swing components)
> are not, and will never, be supported.

If you're writing an IntelliJ Platform plugin, you should use the `SwingBridgeTheme` instead of a standalone theme.

#### Accessing icons

When you want to draw an icon from the resources, you should use a `PainterProvider`. Reading an icon from the IDE is
as easy as using the `retrieveStatefulIcon()` and `retrieveStatelessIcon()`:

```kotlin
val svgLoader = service<SwingBridgeService>().svgLoader
val painterProvider = retrieveStatelessIcon("icons/bot-toolwindow.svg", svgLoader, iconData)
```
5 changes: 2 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ val sarif: Configuration by configurations.creating {

dependencies {
sarif(projects.core)
sarif(projects.composeUtils)
sarif(projects.samples.standalone)
sarif(projects.themes.intUi.intUiStandalone)
sarif(projects.themes.intUi.intUiCore)
sarif(projects.intUi.intUiStandalone)
sarif(projects.intUi.intUiCore)
}

tasks {
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/jewel-publish.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
@file:Suppress("UnstableApiUsage")

plugins {
kotlin("jvm")
`maven-publish`
id("org.jetbrains.dokka")
id("jewel")
}

val sourcesJar by tasks.registering(Jar::class) {
Expand Down
11 changes: 0 additions & 11 deletions compose-utils/build.gradle.kts

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
plugins {
jewel
`jewel-publish`
alias(libs.plugins.composeDesktop)
alias(libs.plugins.kotlinSerialization)
}

dependencies {
api(projects.composeUtils)
api(compose.desktop.common)
api(compose.desktop.currentOs)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.jetbrains.jewel.util

import androidx.compose.ui.Modifier

inline fun Modifier.appendIf(precondition: Boolean, action: Modifier.() -> Modifier) =
if (precondition) action() else this
4 changes: 2 additions & 2 deletions ide-laf-bridge/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
plugins {
alias(libs.plugins.composeDesktop)
jewel
`jewel-publish`
alias(libs.plugins.composeDesktop)
}

dependencies {
api(projects.themes.intUi.intUiStandalone)
api(projects.intUi.intUiStandalone)
compileOnly(libs.bundles.idea)

testImplementation(compose.desktop.uiTestJUnit4)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
@file:Suppress("UnstableApiUsage")

plugins {
jewel
`jewel-publish`
alias(libs.plugins.composeDesktop)
`intellij-theme-generator`
}

dependencies {
api(projects.core)
api(projects.composeUtils)
}

intelliJThemeGenerator {
Expand All @@ -35,4 +35,3 @@ tasks {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}

Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
plugins {
jewel
`jewel-publish`
alias(libs.plugins.composeDesktop)
}

dependencies {
api(projects.themes.intUi.intUiCore)
api(projects.intUi.intUiCore)
}
2 changes: 0 additions & 2 deletions samples/ide-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,5 @@ repositories {
}

dependencies {
implementation(compose.desktop.currentOs)
implementation(projects.themes.intUi.intUiStandalone)
implementation(projects.ideLafBridge)
}
2 changes: 1 addition & 1 deletion samples/standalone/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
}

dependencies {
implementation(projects.themes.intUi.intUiStandalone)
implementation(projects.intUi.intUiStandalone)
}

compose.desktop {
Expand Down
Loading