mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-19 01:51:21 +08:00
fix(jetbrains): separate session backdrop from editor
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/kilo-jetbrains": patch
|
||||
---
|
||||
|
||||
Keep JetBrains session prompts visible in themes where the panel and editor backgrounds match.
|
||||
@@ -299,6 +299,7 @@ inside the session. This avoids fragile component-hierarchy coupling and prevent
|
||||
theme-specific artifacts in transparent/rounded Swing painting.
|
||||
|
||||
- `SessionRootPanel` is the primary opaque backdrop. It overrides `getBackground()` and returns `SessionUiStyle.Colors.sessionBackground()`.
|
||||
- `sessionBackground()` follows the panel background, but when that equals the raised editor surface (`codeBlockBackground()`) — e.g. Islands Dark/Darcula, where panel and editor backgrounds are identical — it shifts by `SESSION_DELTA` via `UiStyle.Colors.contrast` (lighter in dark themes, darker in light) so the prompt bubble/input and other raised surfaces stay visible. This is a universal fallback, not a per-theme override.
|
||||
- `SessionRootPanel.Blocker` is the only other session-background opaque panel. It also overrides `getBackground()` with `sessionBackground()` for modal blocking.
|
||||
- Scroll panes, viewports, transcript layout panels, message lists, turn containers, wrapper panels, and card bodies should be non-opaque unless they intentionally paint a distinct surface.
|
||||
- `applyStyle(style)` must not assign session-background colors. It may update fonts, foregrounds, editor colors, and other non-background styling. Background colors that must be dynamic should come from `getBackground()` or custom painting.
|
||||
|
||||
+22
-11
@@ -19,20 +19,31 @@ object SessionUiStyle {
|
||||
private const val HINT_BOOST = 0.35f
|
||||
|
||||
/**
|
||||
* Fallback recess applied to the editor background only if the panel-background key is ever
|
||||
* missing. [sessionBackground] normally follows the panel background; this keeps it from
|
||||
* falling through to `JBColor.PanelBackground`'s hardcoded white while defaults are provisional.
|
||||
* Recess applied to the raised editor surface to derive a distinct backdrop. Used both when
|
||||
* the panel-background key is missing and when the panel background is identical to the
|
||||
* raised surface (e.g. Islands Dark/Darcula), so the prompt bubble/input and other raised
|
||||
* surfaces still stand out. [UiStyle.Colors.contrast] lightens dark themes and darkens light
|
||||
* themes, matching how generic themes separate the backdrop from editor content.
|
||||
*/
|
||||
private const val SESSION_DELTA = 8
|
||||
|
||||
/** Whole session backdrop: follows the panel (chrome) background, distinct from raised surfaces. */
|
||||
fun sessionBackground(): Color = JBColor.namedColor(
|
||||
"Kilo.Session.background",
|
||||
JBColor.lazy {
|
||||
UIManager.getColor("Panel.background")
|
||||
?: UiStyle.Colors.contrast(UiStyle.Colors.editorBackground(), SESSION_DELTA)
|
||||
},
|
||||
)
|
||||
/**
|
||||
* Whole session backdrop: follows the panel (chrome) background, distinct from raised
|
||||
* surfaces. When the panel background matches the raised surface — so raised surfaces would
|
||||
* be invisible against it — the backdrop is shifted by [SESSION_DELTA] instead.
|
||||
*
|
||||
* Not a `namedColor`: `JBColor.namedColor` resolves through theme `"*"` wildcard rules by
|
||||
* suffix (`name.endsWith("background")`), so any theme with a `*.background` rule would
|
||||
* hijack this key and skip the fallback below. We read an exact override key ourselves and
|
||||
* otherwise compute the backdrop, wrapped in `JBColor.lazy` so it re-resolves on LaF changes.
|
||||
*/
|
||||
fun sessionBackground(): Color = JBColor.lazy {
|
||||
UIManager.getColor("Kilo.Session.background") ?: run {
|
||||
val raised = codeBlockBackground()
|
||||
val panel = UIManager.getColor("Panel.background") ?: raised
|
||||
if (panel.rgb == raised.rgb) UiStyle.Colors.contrast(raised, SESSION_DELTA) else panel
|
||||
}
|
||||
}
|
||||
|
||||
/** Single raised surface (code blocks, tool/shell output, prompt bubble, prompt input): the editor background. */
|
||||
fun codeBlockBackground(): Color = JBColor.namedColor(
|
||||
|
||||
+1
-10
@@ -481,17 +481,8 @@ class MessageView(
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||
val arc = JBUI.scale(JBUI.getInt("Button.arc", SessionUiStyle.View.Prompt.CORNER_ARC))
|
||||
val pt = if (box === this) Point() else SwingUtilities.convertPoint(box, Point(), this)
|
||||
val bg = SessionUiStyle.View.Prompt.bgColor(style)
|
||||
g2.color = bg
|
||||
g2.color = SessionUiStyle.View.Prompt.bgColor(style)
|
||||
g2.fillRoundRect(pt.x, pt.y, box.width, box.height, arc, arc)
|
||||
// When the prompt shares the session background there is no fill contrast, so draw the
|
||||
// outline to keep the bubble visible.
|
||||
if (bg.rgb == SessionUiStyle.Colors.sessionBackground().rgb) {
|
||||
val w = box.width - 1
|
||||
val h = box.height - 1
|
||||
g2.color = SessionUiStyle.View.Outline.color()
|
||||
if (w > 0 && h > 0) g2.drawRoundRect(pt.x, pt.y, w, h, arc, arc)
|
||||
}
|
||||
} finally {
|
||||
g2.dispose()
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package ai.kilocode.client.session.ui.style
|
||||
|
||||
import ai.kilocode.client.ui.UiStyle
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import java.awt.Color
|
||||
import javax.swing.UIManager
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class SessionUiStyleTest : BasePlatformTestCase() {
|
||||
|
||||
fun `test session background shifts when panel matches the raised editor surface`() {
|
||||
val raised = SessionUiStyle.Colors.codeBlockBackground()
|
||||
val previous = UIManager.getColor("Panel.background")
|
||||
try {
|
||||
// Force the Islands case: the panel/backdrop is exactly the raised editor surface.
|
||||
UIManager.put("Panel.background", Color(raised.rgb))
|
||||
val bg = SessionUiStyle.Colors.sessionBackground()
|
||||
|
||||
// When the panel equals the raised surface the backdrop must shift to a distinct color:
|
||||
// lighter in dark themes, darker in light themes.
|
||||
assertTrue("Backdrop must not equal the raised surface", raised.rgb != bg.rgb)
|
||||
val dark = raised.red * 0.299 + raised.green * 0.587 + raised.blue * 0.114 < 128
|
||||
if (dark) {
|
||||
assertTrue("Dark themes shift the backdrop lighter", brighter(bg, raised))
|
||||
} else {
|
||||
assertTrue("Light themes shift the backdrop darker", darker(bg, raised))
|
||||
}
|
||||
} finally {
|
||||
UIManager.put("Panel.background", previous)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test session background follows the panel when it differs from the raised surface`() {
|
||||
val previous = UIManager.getColor("Panel.background")
|
||||
try {
|
||||
val panel = UiStyle.Colors.contrast(SessionUiStyle.Colors.codeBlockBackground(), 40)
|
||||
UIManager.put("Panel.background", panel)
|
||||
|
||||
assertEquals(panel.rgb, SessionUiStyle.Colors.sessionBackground().rgb)
|
||||
} finally {
|
||||
UIManager.put("Panel.background", previous)
|
||||
}
|
||||
}
|
||||
|
||||
private fun brighter(shifted: Color, base: Color) =
|
||||
shifted.red >= base.red && shifted.green >= base.green && shifted.blue >= base.blue
|
||||
|
||||
private fun darker(shifted: Color, base: Color) =
|
||||
shifted.red <= base.red && shifted.green <= base.green && shifted.blue <= base.blue
|
||||
}
|
||||
Reference in New Issue
Block a user