Jewel旨在以Compose for Desktop重新创建IntelliJ平台的"新UI"Swing外观和感觉,提供针对桌面优化的主题和组件集。
[!警告]
该项目正在积极开发中,在考虑用于生产用途时建议谨慎。您可以使用它,但应该预期API会经常变更,东西可能会移动和/或损坏,以及所有这些常见情况。不保证跨版本的二进制兼容性,API仍在变化中且可能会更改。
目前,IntelliJ平台不正式支持使用Compose for Desktop编写第三方IntelliJ插件。它应该可以工作,但您的体验可能会有所不同,如果出现问题,您将无法获得支持。
使用时风险自负!
Jewel提供了可在任何Compose for Desktop应用程序中使用的IntelliJ平台主题实现。此外,它还有一个Swing LaF桥接器,只能在IntelliJ平台中使用(即用于创建IDE插件),但会自动将当前的Swing LaF镜像到Compose中,以获得原生外观的一致UI。
<br/>[!提示] <a href="https://www.droidcon.com/2023/11/15/meet-jewelcreate-ide-plugins-in-compose/"> <img src="https://i.vimeocdn.com/video/1749849437-f275e0337faca5cedab742ea157abbafe5a0207d3a59db891a72b6180ce13a6c-d?mh=120" align="left" /> </a>
如果您想了解更多关于Jewel和Compose for Desktop的信息,以及为什么它们是满足您桌面UI需求的出色现代解决方案,请查看Jewel贡献者Sebastiano和Chris的这个演讲。
它涵盖了为什么Compose是一个可行的选择,以及Jewel项目的概述,还有一些真实世界的使用案例。<br clear="left" />
首先要添加必要的Gradle插件,包括Compose Multiplatform插件。你需要在settings.gradle.kts
中添加一个自定义仓库:
pluginManagement { repositories { google() gradlePluginPortal() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") mavenCentral() } }
然后,在你的应用的build.gradle.kts
中:
plugins { // 应与Jewel中的Kotlin和Compose依赖保持一致 kotlin("jvm") version "1.9.21" id("org.jetbrains.compose") version "1.6.0-dev1440" } repositories { maven("https://packages.jetbrains.team/maven/p/kpm/public/") // 你需要的任何其他仓库(例如 mavenCentral()) }
[!警告] 如果你使用约定插件来配置项目,可能会遇到诸如这样的问题。要解决它,请确保插件只初始化一次 — 例如,在根
build.gradle.kts
中用apply false
声明它们,然后在所有需要它们的子模块中应用它们。
要在你的应用中使用Jewel,你只需添加相关的依赖项。有两种情况:独立的Compose for Desktop应用,和IntelliJ Platform插件。
如果你正在编写独立应用,那么你应该依赖最新的int-ui-standalone-*
构件:
dependencies { // 查看 https://github.com/JetBrains/Jewel/releases 获取发布说明 implementation("org.jetbrains.jewel:jewel-int-ui-standalone-[最新平台版本]:[jewel版本]") // 可选,用于自定义装饰窗口: implementation("org.jetbrains.jewel:jewel-int-ui-decorated-window-[最新平台版本]:[jewel版本]") // 不要引入Material(我们使用Jewel) implementation(compose.desktop.currentOs) { exclude(group = "org.jetbrains.compose.material") } }
对于IntelliJ Platform插件,你应该依赖适当的ide-laf-bridge-*
构件:
<br/>dependencies { // 查看 https://github.com/JetBrains/Jewel/releases 获取发布说明 // 平台版本是支持的主要IJP版本(例如,232或233分别代表2023.2和2023.3) implementation("org.jetbrains.jewel:jewel-ide-laf-bridge-[平台版本]:[jewel版本]") // 不要引入Material(我们使用Jewel)和Coroutines(IDE有自己的) api(compose.desktop.currentOs) { exclude(group = "org.jetbrains.compose.material") exclude(group = "org.jetbrains.kotlinx") } }
<br/>[!提示] 使用版本目录更容易 — 你可以使用Jewel的版本目录作为参考。
Jewel不官方支持使用ProGuard来最小化和/或混淆你的代码,目前也没有这样的计划。 话虽如此,人们报告在使用它时取得了成功。请注意,不能保证它会继续有效, 而且你肯定需要制定一些规则。我们不提供任何官方规则集,但这些规则已知 对某些人有效: https://github.com/romainguy/kotlin-explorer/blob/main/compose-desktop.pro
[!重 要] 我们不会接受因使用ProGuard或类似工具而导致的问题的错误报告。
Jewel正在持续开发中,我们专注于支持我们内部使用的Compose版本。 你可以在libs.versions.toml中看到最新支持的版本。
不同版本的Compose不能保证与不同版本的Jewel一起工作。
使用的Compose Compiler版本是与给定Kotlin版本兼容的最新版本。请查看 这里的Compose Compiler发布说明,其中指出了兼容性。
支持的最低Kotlin版本由支持的最低IntelliJ IDEA平台决定。
该项目分为多个模块:
buildSrc
包含构建逻辑,包括:
jewel
和jewel-publish
配置插件jewel-check-public-api
和jewel-linting
配置插件foundation
包含基础的Jewel功能:
SelectableLazyColumn
, BasicLazyTree
)JewelTheme
接口ui
包含所有样式化组件和自定义画家逻辑decorated-window
包含在JetBrains Runtime上进行自定义窗口装饰的基本、无样式功能int-ui
包含两个模块:
int-ui-standalone
有一个可以在任何Compose for Desktop应用中使用的Int UI样式值的独立版本int-ui-decorated-window
有一个可以在任何Compose for Desktop应用中使用的自定义窗口装饰的Int UI样式值的独立版本ide-laf-bridge
包含用于IntelliJ Platform插件的Swing LaF桥(详见下文)markdown
包含几个模块:
core
使用类似GitHub的样式,用Jewel解析和渲染Markdown文档的核心逻辑extension
包含几个可用于添加更多功能的基本CommonMark规范的扩展ide-laf-bridge-styling
包含Markdown渲染器的IntelliJ Platform桥主题int-ui-standalone-styling
包含Markdown渲染器的独立Int UI主题samples
包含展示可用组件的示例应用:
standalone
是一个常规CfD应用,使用独立主题定义和自定义窗口装饰ide-plugin
是一个展示如何使用Swing桥的IntelliJ插件主分支上的代码是针对当前最新的IntelliJ Platform版本开发和测试的。
当新的主要版本的EAP开始时,我们会切出一个releases/xxx
发布分支,其中xxx
是跟踪的主要
IJP版本。此时,主分支开始跟踪最新可用的主要IJP版本,并根据需要将更改cherry-pick到每个发布分支。
所有活跃的发布分支都具有相同的功能(在相应的IJP版本支持的情况下),但可能在平台版本特定的修复和内部实现上有所不同。
独立的Int UI主题将始终以与最新主要IJP版本相同的方式工作;发布分支将不
包括int-ui
模块,该模块始终从主分支发布。
Jewel的发布总是从主分支上的标签切出;然后每个releases/xxx
分支的HEAD被标记为
[mainTag]-xxx
,并用于发布该主要IJP版本的构件。
[!重要] 我们只支持每个主要IJP版本的最新构建。例如,如果最新的233版本是2023.3.3, 我们只保证Jewel在该版本上工作。2023.3.0–2023.3.2版本可能有效,也可能无效。
[!注意] 当你针对Android Studio时,你可能会遇到问题,因为Studio附带了自己的(较旧的)Jewel 和Compose for Desktop版本。如果你想针对Android Studio,在Studio不再在类路径上泄露该依赖之前, 你需要对CfD和Jewel依赖进行阴影处理。你可以查看Package Search插件如何实现阴影处理。
独立主题可以在任何Compose for Desktop应用中使用。你可以像使用普通主题一样使用它,并且可以随心所欲地自定义它。 默认情况下,它与官方Int UI规范相匹配。
有关如何设置独立应用的示例,你可以参考standalone
示例。
[!警告] 请注意,Jewel需要JetBrains Runtime才能正确工作。一些功能如字体加载依赖于它, 因为它具有其他JDK中不可用的额外功能和UI功能补丁。 我们不支持在任何其他JDK上运行Jewel。
要在非IntelliJ Platform环境中使用Jewel组件,你需要将UI层次结构包装在IntUiTheme
可组合函数中:
IntUiTheme(isDark = false) { // ... }
如果你想对主题有更多控制,可以使用其他IntUiTheme
重载,就像独立示例所做的那样。
JetBrains Runtime允许窗口具有自定义装饰,而不是常规标题栏。
独立示例应用展示了如何轻松获得类似JetBrains IDE的外观;如果你想进行非常
自定义,你只需依赖decorated-window
模块,其中包含所有必需的原语,但不包含Int UI样式。
要获得类似IntelliJ的自定义标题栏,你需要将窗口装饰样式传递给主题调用,并在主题的顶层
添加DecoratedWindow
可组合函数:
IntUiTheme( theme = themeDefinition, styling = ComponentStyling.default().decoratedWindow( titleBarStyle = TitleBarStyle.light() ), ) { DecoratedWindow( onCloseRequest = { exitApplication() }, ) { // ... } }
Jewel包含一个与IDE正确集成的关键元素:Swing组件 — 主题和LaF — 与Compose世界之间的桥梁。
这个桥梁确保我们获取当前IntelliJ主题中定义的颜色、排版、度量和图像,并将它们应用到Compose组件中。 这意味着Jewel将自动适应使用标准主题 机制的IntelliJ Platform主题。
[!注意] 使用非标准机制(例如为Swing组件提供自定义UI实现)的IntelliJ主题不受支持,也永远不会受支持。
如果你正在编写IntelliJ Platform插件,你应该使用SwingBridgeTheme
而不 是独立主题:
SwingBridgeTheme { // ... }
要在IntelliJ Platform中使用Jewel,你应该依赖适当的jewel-ide-laf-bridge-*
构件,
它将带来必要的传递依赖。以下是当前支持的IntelliJ Platform版本和相应桥接代码所在的分支:
IntelliJ Platform 版本 | 使用的分支 |
---|---|
2024.2 (beta 1+) | main |
2024.1 (EAP 3+) | releases/241 |
2023.3 | releases/233 |
2023.2 (已弃用) | archived-releases/232 |
2023.1 或更早版本 | 不支持 |
关于如何设 置 IntelliJ 插件的示例,你可以参考 ide-plugin
样例。
在为 IntelliJ Platform 或独立应用构建时,你可以使用基于键的图标加载 API,它允许你以跨目标的方式加载图标。
要加载图标,你可以使用 Icon
可组合函数并提供带有资源路径的 PathIconKey
:
// 等同于旧的基于路径的 API Icon(PathIconKey("icons/myIcon.svg"), contentDescription = "...")
如果你想获得更好的体验,不必到处处理字符串和键,你可以构建自己的 *IconsKeys
文件。以我们的 AllIconsKeys
文件为参考。你可以手动维护它,或者根据需要自动生成它。
如果你需要在独立应用中使用标准的 IntelliJ Platform 图标,比如那些在 AllIcons
中找到的图标,你需要进行一些设置以确保图标存在于类路径中并可以作为资源加载。
在你的构建脚本中添加以下内容:
dependencies { implementation("com.jetbrains.intellij.platform:icons:[ijpVersion]") // ... } repositories { // 根据你是否使用稳定版的 IJP 选择以下两者之一 maven("https://www.jetbrains.com/intellij-repository/releases") maven("https://www.jetbrains.com/intellij-repository/snapshots") }
[!注意] 如果你的目标是 IntelliJ 插件,你不需要这个额外的设置,因为平台本身提供了图标。
一旦图标在类路径上,你就可以使用 PlatformIcon
可组合函数:
// 对于在 AllIcons 中找到的平台图标 PlatformIcon(AllIconsKeys.Nodes.ConfigFolder, "taskGroup")
要使用的正确 IconKey
取决于图标是否有旧 UI 和新 UI 变体:
PathIconKey
表示来自资源的没有旧 UI 和新 UI 变体的图标IntelliJIconKey
类似,但为旧 UI 和新 UI 变体提供路径如果你只针对新 UI,你可以使用 PathIconKey
或 IntelliJIconKey
来加载图标。如果你针对旧 UI,你需要使用 IntelliJIconKey
。