[ui] IJPL-203342 Islands: Navigation bar has wrong background color if placed on top or project gradient/toolbar is off

GitOrigin-RevId: ff04cb364f9147247da7a125cb9a293da6afe76b
This commit is contained in:
Pavel Porvatov
2025-10-27 15:50:36 +00:00
committed by intellij-monorepo-bot
parent 8f9636038e
commit 0aa1646e4c
10 changed files with 82 additions and 46 deletions
@@ -13,8 +13,8 @@ import com.intellij.openapi.actionSystem.ex.ComboBoxAction
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.UI
import com.intellij.openapi.application.impl.BorderPainterHolder
import com.intellij.openapi.application.impl.InternalUICustomization
import com.intellij.openapi.application.impl.TopNavBarComponentFacade
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.IdeRootPaneNorthExtension
import com.intellij.openapi.wm.StatusBar
@@ -277,7 +277,7 @@ internal open class MyNavBarWrapperPanel(private val project: Project, useAsComp
}
internal class MyTopNavBarWrapperPanel(project: Project, useAsComponent: Boolean) :
MyNavBarWrapperPanel(project, useAsComponent), TopNavBarComponentFacade {
MyNavBarWrapperPanel(project, useAsComponent), BorderPainterHolder {
override var borderPainter: BorderPainter = DefaultBorderPainter()
@@ -447,7 +447,7 @@ private object TopNavBarMode : NavBarMode {
return withContext(Dispatchers.EDT) {
setStatusBarCentralWidget(statusBar, null)
val panel = MyTopNavBarWrapperPanel(project, useAsComponent = true)
InternalUICustomization.getInstance()?.configureTopNavBar(panel)
InternalUICustomization.getInstance()?.registerWindowBackgroundComponent(panel)
panel
}
}
@@ -95,7 +95,11 @@ open class InternalUICustomization {
open fun configureMainToolbar(toolbar: MainToolbar) {}
open fun configureTopNavBar(navBar: TopNavBarComponentFacade) {}
/**
* For Islands theme: the components are painted with the IDE background or gradient if set.
* For other themes: has no effect
*/
open fun registerWindowBackgroundComponent(component: JComponent) {}
open fun getEditorToolbarButtonLook(): ActionButtonLook? = null
@@ -173,6 +177,6 @@ open class InternalUICustomization {
}
@ApiStatus.Internal
interface TopNavBarComponentFacade {
interface BorderPainterHolder {
var borderPainter: BorderPainter
}
@@ -25,12 +25,22 @@ import javax.swing.JComponent
internal class IslandsGradientPainter(private val frame: IdeFrame, private val mainColor: Color, private val enabled: () -> Boolean) : AbstractPainter() {
/**
* The list of auto replaced colors. Should contain only very specific colors, don't add widely used like `Panel.background`
*/
private val islandsGradientColors = setOf(
// Root components
"MainWindow.background",
"MainToolbar.background",
"MainToolbar.inactiveBackground",
"ToolWindow.Stripe.background",
"StatusBar.background")
"StatusBar.background",
// Nav bar
"StatusBar.Breadcrumbs.hoverBackground",
"StatusBar.Breadcrumbs.selectionBackground",
"StatusBar.Breadcrumbs.selectionInactiveBackground"
)
private val projectWindowCustomizer = ProjectWindowCustomizerService.getInstance()
@@ -10,32 +10,28 @@ import com.intellij.ide.ui.experimental.ExperimentalUiCollector
import com.intellij.openapi.actionSystem.DataSink
import com.intellij.openapi.actionSystem.UiDataProvider
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.impl.BorderPainterHolder
import com.intellij.openapi.application.impl.InternalUICustomization
import com.intellij.openapi.application.impl.ToolWindowUIDecorator
import com.intellij.openapi.application.impl.TopNavBarComponentFacade
import com.intellij.openapi.editor.impl.EditorHeaderComponent
import com.intellij.openapi.editor.impl.SearchReplaceFacade
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter
import com.intellij.openapi.fileEditor.impl.EditorsSplitters
import com.intellij.openapi.ui.Divider
import com.intellij.openapi.ui.OnePixelDivider
import com.intellij.openapi.ui.Splittable
import com.intellij.openapi.ui.*
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.SystemInfoRt
import com.intellij.openapi.wm.*
import com.intellij.openapi.wm.ex.ToolWindowManagerEx
import com.intellij.openapi.wm.impl.*
import com.intellij.openapi.wm.impl.content.ContentLayout
import com.intellij.openapi.wm.impl.customFrameDecorations.header.CustomHeader
import com.intellij.openapi.wm.impl.customFrameDecorations.header.CustomWindowHeaderUtil
import com.intellij.openapi.wm.impl.customFrameDecorations.header.MacToolbarFrameHeader
import com.intellij.openapi.wm.impl.headertoolbar.MainToolbar
import com.intellij.openapi.wm.impl.status.IdeStatusBarImpl
import com.intellij.toolWindow.ToolWindowButtonManager
import com.intellij.toolWindow.ToolWindowPane
import com.intellij.toolWindow.ToolWindowPaneNewButtonManager
import com.intellij.toolWindow.ToolWindowToolbar
import com.intellij.toolWindow.xNext.island.XNextIslandHolder
import com.intellij.ui.*
import com.intellij.ui.components.JBLayeredPane
@@ -64,6 +60,10 @@ import javax.swing.SwingConstants
import javax.swing.SwingUtilities
import javax.swing.border.Border
private data class WindowBackgroundComponentData(val origOpaque: Boolean, val origBackground: Color?)
private val WINDOW_BACKGROUND_COMPONENT_KEY: Key<WindowBackgroundComponentData> = Key.create("Islands.WINDOW_BACKGROUND_COMPONENT_KEY")
internal class IslandsUICustomization : InternalUICustomization() {
private val isIslandsAvailable = ExperimentalUI.isNewUI()
@@ -447,9 +447,11 @@ internal class IslandsUICustomization : InternalUICustomization() {
}
}
override fun configureTopNavBar(navBar: TopNavBarComponentFacade) {
override fun registerWindowBackgroundComponent(component: JComponent) {
component.putUserData(WINDOW_BACKGROUND_COMPONENT_KEY, WindowBackgroundComponentData(component.isOpaque, component.background))
if (isManyIslandEnabled) {
configureMainFrameChildren(navBar as Component, true)
configureMainFrameChildren(component, true)
}
}
@@ -464,29 +466,25 @@ internal class IslandsUICustomization : InternalUICustomization() {
private fun configureMainFrameChildren(component: Component, install: Boolean) {
when (component) {
is ToolWindowToolbar -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
is CustomHeader -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
is MacToolbarFrameHeader -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
is IdeStatusBarImpl -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
is MainToolbar -> {
is BorderPainterHolder -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
is ToolWindowPane -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
is TopNavBarComponentFacade -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
is WindowTabsComponent -> {
component.borderPainter = if (install) inactivePainter else DefaultBorderPainter()
}
if (component is JComponent) {
val data = component.getUserData(WINDOW_BACKGROUND_COMPONENT_KEY)
if (data != null) {
if (install) {
component.isOpaque = true
component.background = getMainBackgroundColor()
}
else {
component.isOpaque = data.origOpaque
component.background = data.origBackground
}
}
}
}
@@ -6,6 +6,7 @@ import com.intellij.accessibility.AccessibilityUtils
import com.intellij.icons.AllIcons
import com.intellij.openapi.MnemonicHelper
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.impl.BorderPainterHolder
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.ui.JBPopupMenu
import com.intellij.openapi.util.NlsActions
@@ -48,7 +49,7 @@ internal fun updateWinControlsTheme(background: Color, customTitleBar: CustomTit
customTitleBar.putProperty("controls.background.hovered", UIManager.getColor("TitlePane.Button.hoverBackground"))
}
internal sealed class CustomHeader(@JvmField internal val window: Window) : JPanel() {
internal sealed class CustomHeader(@JvmField internal val window: Window) : JPanel(), BorderPainterHolder {
companion object {
val H: Int
get() = 12
@@ -127,7 +128,7 @@ internal sealed class CustomHeader(@JvmField internal val window: Window) : JPan
createProductIcon()
}
internal var borderPainter: BorderPainter = DefaultBorderPainter()
override var borderPainter: BorderPainter = DefaultBorderPainter()
init {
isOpaque = true
@@ -11,6 +11,7 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.UI
import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.application.impl.BorderPainterHolder
import com.intellij.openapi.application.impl.InternalUICustomization
import com.intellij.openapi.wm.impl.ToolbarHolder
import com.intellij.openapi.wm.impl.customFrameDecorations.header.titleLabel.SimpleCustomDecorationPath
@@ -51,7 +52,7 @@ internal class MacToolbarFrameHeader(
private val frame: JFrame,
private val rootPane: JRootPane,
private val isAlwaysCompact: Boolean = false,
) : JPanel(), MainFrameCustomHeader, ToolbarHolder, UISettingsListener {
) : JPanel(), MainFrameCustomHeader, ToolbarHolder, UISettingsListener, BorderPainterHolder {
private var view: HeaderView
private val updateRequests = MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
@@ -72,7 +73,7 @@ internal class MacToolbarFrameHeader(
val customTitleBar: WindowDecorations.CustomTitleBar?
internal var borderPainter: BorderPainter = DefaultBorderPainter()
override var borderPainter: BorderPainter = DefaultBorderPainter()
init {
// a colorful toolbar
@@ -27,6 +27,7 @@ import com.intellij.openapi.actionSystem.toolbarLayout.ToolbarLayoutStrategy
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.UiWithModelAccess
import com.intellij.openapi.application.impl.BorderPainterHolder
import com.intellij.openapi.application.impl.InternalUICustomization
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.keymap.impl.ui.ActionsTreeUtil
@@ -112,12 +113,12 @@ class MainToolbar(
isOpaque: Boolean = false,
background: Color? = null,
private val isFullScreen: () -> Boolean,
) : JPanel(HorizontalLayout(layoutGap)) {
) : JPanel(HorizontalLayout(layoutGap)), BorderPainterHolder {
private val flavor: MainToolbarFlavor
private val widthCalculationListeners = mutableSetOf<ToolbarWidthCalculationListener>()
private val cachedWidths by lazy { ConcurrentHashMap<String, Int>() }
internal var borderPainter: BorderPainter = DefaultBorderPainter()
override var borderPainter: BorderPainter = DefaultBorderPainter()
init {
this.background = background
@@ -8,6 +8,7 @@ import com.intellij.ide.ui.LafManagerListener
import com.intellij.ide.ui.UISettings
import com.intellij.ide.ui.UISettingsListener
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.impl.BorderPainterHolder
import com.intellij.openapi.application.impl.InternalUICustomization
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
@@ -65,7 +66,7 @@ class ToolWindowPane private constructor(
frame: JFrame,
val paneId: String,
@field:JvmField internal val buttonManager: ToolWindowButtonManager,
) : JLayeredPane(), UISettingsListener {
) : JLayeredPane(), UISettingsListener, BorderPainterHolder {
companion object {
const val TEMPORARY_ADDED: String = "TEMPORARY_ADDED"
@@ -125,7 +126,8 @@ class ToolWindowPane private constructor(
internal val frame: JFrame
internal var borderPainter: BorderPainter = DefaultBorderPainter()
override var borderPainter: BorderPainter = DefaultBorderPainter()
/**
* This panel is the layered pane where all sliding tool windows are located. The DEFAULT
* layer contains splitters. The PALETTE layer contains all sliding tool windows.
@@ -3,6 +3,7 @@
package com.intellij.toolWindow
import com.intellij.accessibility.AccessibilityUtils
import com.intellij.openapi.application.impl.BorderPainterHolder
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.VerticalFlowLayout
import com.intellij.openapi.util.NlsSafe
@@ -29,7 +30,8 @@ import javax.swing.border.Border
import kotlin.math.max
@ApiStatus.Internal
abstract class ToolWindowToolbar(private val isPrimary: Boolean, val anchor: ToolWindowAnchor) : JBPanel<ToolWindowToolbar>() {
abstract class ToolWindowToolbar(private val isPrimary: Boolean, val anchor: ToolWindowAnchor) : JBPanel<ToolWindowToolbar>(),
BorderPainterHolder {
lateinit var defaults: List<String>
internal abstract val bottomStripe: AbstractDroppableStripe
@@ -42,7 +44,7 @@ abstract class ToolWindowToolbar(private val isPrimary: Boolean, val anchor: Too
private var hasVisibleButtons = false
private val visibleButtonsListeners = mutableListOf<() -> Unit>()
internal var borderPainter: BorderPainter = DefaultBorderPainter()
override var borderPainter: BorderPainter = DefaultBorderPainter()
protected open fun init() {
layout = myResizeManager.createLayout()
@@ -6,6 +6,7 @@ import com.intellij.ide.IdeBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.impl.BorderPainterHolder;
import com.intellij.openapi.application.impl.InternalUICustomization;
import com.intellij.openapi.components.ComponentManagerEx;
import com.intellij.openapi.project.DumbAwareAction;
@@ -39,7 +40,10 @@ import com.intellij.ui.tabs.UiDecorator;
import com.intellij.ui.tabs.impl.*;
import com.intellij.ui.tabs.impl.singleRow.WindowTabsLayout;
import com.intellij.ui.tabs.impl.themes.DefaultTabTheme;
import com.intellij.util.ui.*;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.JBFont;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import kotlinx.coroutines.CoroutineScope;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@@ -55,7 +59,7 @@ import java.beans.PropertyChangeListener;
import java.util.*;
@ApiStatus.Internal
public final class WindowTabsComponent extends JBTabsImpl {
public final class WindowTabsComponent extends JBTabsImpl implements BorderPainterHolder {
private static final String TITLE_LISTENER_KEY = "TitleListener";
public static final String CLOSE_TAB_KEY = "CloseTab";
@@ -67,7 +71,7 @@ public final class WindowTabsComponent extends JBTabsImpl {
private final Disposable myParentDisposable;
private final Map<IdeFrameImpl, Integer> myIndexes = new HashMap<>();
public BorderPainter borderPainter = new DefaultBorderPainter();
private BorderPainter borderPainter = new DefaultBorderPainter();
public WindowTabsComponent(@NotNull IdeFrameImpl nativeWindow, @Nullable Project project, @NotNull Disposable parentDisposable) {
super(project, parentDisposable);
@@ -94,6 +98,19 @@ public final class WindowTabsComponent extends JBTabsImpl {
installDnD();
}
@ApiStatus.Internal
@Override
public @NotNull BorderPainter getBorderPainter() {
return borderPainter;
}
@ApiStatus.Internal
@Override
public void setBorderPainter(@NotNull BorderPainter painter) {
this.borderPainter = painter;
}
private static @NotNull Insets getContentInsets() {
InternalUICustomization customization = InternalUICustomization.getInstance();
if (customization != null) {