diff --git a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt index 188cd51a1719..19be1e87d440 100644 --- a/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt +++ b/platform/platform-impl/src/com/intellij/ide/ProjectWindowCustomizerService.kt @@ -523,6 +523,7 @@ private class ProjectWindowCustomizerListener : ProjectActivity, UISettingsListe } override fun uiSettingsChanged(uiSettings: UISettings) { + InternalUICustomization.getInstance()?.updateBackgroundPainter() ProjectWindowCustomizerService.getInstance().update(uiSettings.differentiateProjects) } } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java b/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java index 07e9df9cbd09..af6d87f37d43 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/QuickChangeLookAndFeel.java @@ -5,6 +5,7 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; import com.intellij.ide.ui.LafManager; import com.intellij.ide.ui.LafManagerListener; +import com.intellij.ide.ui.TargetUIType; import com.intellij.ide.ui.ThemeListProvider; import com.intellij.ide.ui.laf.UIThemeLookAndFeelInfo; import com.intellij.ide.ui.laf.UiThemeProviderListManager; @@ -43,6 +44,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.util.Collections; import java.util.List; public final class QuickChangeLookAndFeel extends QuickSwitchSchemeAction implements ActionRemoteBehaviorSpecification.Frontend { @@ -72,9 +74,13 @@ public final class QuickChangeLookAndFeel extends QuickSwitchSchemeAction implem @Override protected @NotNull ListPopup createPopup(AnActionEvent e, DefaultActionGroup group, JBPopupFactory.ActionSelectionAid aid) { + UiThemeProviderListManager themeManager = UiThemeProviderListManager.Companion.getInstance(); + List islandThemes = themeManager.getBundledThemeListForTargetUI(TargetUIType.ISLANDS); + if (WelcomeFrame.getInstance() == null && - ContainerUtil.exists(group.getChildren(e), - action -> action instanceof LafChangeAction lafAction && lafAction.myLookAndFeelInfo.isRestartRequired())) { + ContainerUtil.exists(group.getChildren(e), action -> action instanceof LafChangeAction lafAction && + (lafAction.myLookAndFeelInfo.isRestartRequired() || + islandThemes.contains(lafAction.myLookAndFeelInfo)))) { return new PopupFactoryImpl.ActionGroupPopup(null, getPopupTitle(e), group, e.getDataContext(), myActionPlace == null ? ActionPlaces.POPUP : myActionPlace, new PresentationFactory(), ActionPopupOptions.forAid(aid, true, -1, preselectAction()), null) { @@ -113,7 +119,7 @@ public final class QuickChangeLookAndFeel extends QuickSwitchSchemeAction implem if (value instanceof PopupFactoryImpl.ActionItem item) { AnAction action = item.getAction(); if (action instanceof LafChangeAction lafAction) { - checkRestartRequired(lafAction, infos, isSelected, icon1, icon2); + checkRestartRequired(lafAction, infos, islandThemes, isSelected, icon1, icon2); } } } @@ -126,6 +132,7 @@ public final class QuickChangeLookAndFeel extends QuickSwitchSchemeAction implem private static boolean checkRestartRequired(@NotNull LafChangeAction lafAction, @NotNull List> infos, + @NotNull List islandThemes, boolean isSelected, @Nullable JLabel icon1, @Nullable JLabel icon2) { @@ -154,6 +161,9 @@ public final class QuickChangeLookAndFeel extends QuickSwitchSchemeAction implem } return true; } + if (icon1 != null && islandThemes.contains(lafAction.myLookAndFeelInfo)) { + icon1.setIcon(AllIcons.General.Beta); + } return false; } @@ -232,7 +242,8 @@ public final class QuickChangeLookAndFeel extends QuickSwitchSchemeAction implem Object item = ((JList)event.getSource()).getSelectedValue(); if (item instanceof AnActionHolder) { AnAction anAction = ((AnActionHolder)item).getAction(); - if (anAction instanceof LafChangeAction action && !checkRestartRequired(action, infos, false, null, null)) { + if (anAction instanceof LafChangeAction action && + !checkRestartRequired(action, infos, Collections.emptyList(), false, null, null)) { switchAlarm.cancelAllRequests(); switchAlarm.addRequest(() -> { switchLafAndUpdateUI(LafManager.getInstance(), action.myLookAndFeelInfo); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.kt b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.kt index 22251b7b6876..cfa10a3544a6 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.kt @@ -64,7 +64,6 @@ import com.intellij.util.IJSwingUtilities import com.intellij.util.SVGLoader.colorPatcherProvider import com.intellij.util.concurrency.SynchronizedClearableLazy import com.intellij.util.ui.* -import com.intellij.util.ui.StartupUiUtil import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope @@ -499,7 +498,10 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(), } override fun getLookAndFeelCellRenderer(component: JComponent): ListCellRenderer { + val themeManager = UiThemeProviderListManager.getInstance() + val islandThemes = themeManager.getBundledThemeListForTargetUI(TargetUIType.ISLANDS) val welcomeMode = WelcomeFrame.getInstance() != null + return listCellRenderer { toolTipText = null text(value.name) @@ -521,6 +523,9 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(), icon(getDisabledIcon(AllIcons.Actions.Restart, null)) toolTipText = IdeBundle.message("ide.restart.required.comment") } + else if (islandThemes.contains(theme)) { + icon(AllIcons.General.Beta) + } break } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/UiThemeProviderListManager.kt b/platform/platform-impl/src/com/intellij/ide/ui/laf/UiThemeProviderListManager.kt index 0961bbc6762a..fd535c695bd9 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/UiThemeProviderListManager.kt +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/UiThemeProviderListManager.kt @@ -115,6 +115,14 @@ class UiThemeProviderListManager { .mapNotNull { it.theme.get() } } + fun getBundledThemeListForTargetUI(targetUI: TargetUIType): List { + val themes = mutableListOf() + getThemeListForTargetUI(targetUI).forEach { info -> + if (!info.isThemeFromPlugin) themes.add(info) + } + return themes + } + internal fun themeProviderAdded(provider: UIThemeProvider, pluginDescriptor: PluginDescriptor): LafEntry? { if (findLaFByProviderId(provider) != null) { // provider is already registered diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/InternalUICustomization.kt b/platform/platform-impl/src/com/intellij/openapi/application/impl/InternalUICustomization.kt index 65187768a390..66e39f44416b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/InternalUICustomization.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/InternalUICustomization.kt @@ -105,6 +105,8 @@ open class InternalUICustomization { open fun attachIdeFrameBackgroundPainter(frame: IdeFrame, glassPane: IdeGlassPane): Unit = Unit + open fun updateBackgroundPainter() {} + open fun attachIdeFallbackBackgroundPainter(glassPane: IdeGlassPane): Unit = Unit open fun attachDialogFallbackBackgroundPainter(glassPane: IdeGlassPane): Unit = Unit diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ToolWindowUIDecorator.kt b/platform/platform-impl/src/com/intellij/openapi/application/impl/ToolWindowUIDecorator.kt index f5e5003d0244..a4d8b03c5a3a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ToolWindowUIDecorator.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ToolWindowUIDecorator.kt @@ -4,10 +4,11 @@ package com.intellij.openapi.application.impl import org.jetbrains.annotations.ApiStatus import javax.swing.JComponent import javax.swing.JPanel +import javax.swing.border.Border @ApiStatus.Internal open class ToolWindowUIDecorator() { - open fun decorateAndReturnHolder(divider: JComponent, child: JComponent): JComponent? = null + open fun decorateAndReturnHolder(divider: JComponent, child: JComponent, originalBorderBuilder: () -> Border): JComponent? = null open fun createCustomToolWindowPaneHolder(): JPanel = JPanel() } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsGradientPainter.kt b/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsGradientPainter.kt index f5cc2c735e64..4c9688fb74df 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsGradientPainter.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsGradientPainter.kt @@ -18,7 +18,7 @@ import com.intellij.ui.scale.ScaleContext import com.intellij.util.ui.JBUI import java.awt.* -internal class IslandsGradientPainter(private val frame: IdeFrame, private val mainColor: Color) : AbstractPainter() { +internal class IslandsGradientPainter(private val frame: IdeFrame, private val mainColor: Color, private val enabled: () -> Boolean) : AbstractPainter() { private val leftGradientCache: GradientTextureCache = GradientTextureCache() private val rightGradientCache: GradientTextureCache = GradientTextureCache() @@ -26,7 +26,7 @@ internal class IslandsGradientPainter(private val frame: IdeFrame, private val m private var doPaint = true - override fun needsRepaint(): Boolean = true + override fun needsRepaint(): Boolean = enabled() override fun executePaint(component: Component, g: Graphics2D) { if (doPaint) { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsTabPainter.kt b/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsTabPainter.kt index 6d3f4e5f3645..07585d82506e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsTabPainter.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsTabPainter.kt @@ -1,6 +1,7 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.application.impl.islands +import com.intellij.openapi.fileEditor.impl.EditorTabPainterAdapter import com.intellij.ui.ColorUtil import com.intellij.ui.JBColor import com.intellij.ui.paint.RectanglePainter2D @@ -16,10 +17,21 @@ import com.intellij.util.ui.JBUI import java.awt.* import java.awt.geom.RoundRectangle2D -internal class ManyIslandsTabPainterAdapter : TabPainterAdapter { - override val tabPainter: JBTabPainter = ManyIslandsTabPainter() +internal class IslandsTabPainterAdapter(var isEnabled: Boolean) : TabPainterAdapter { + private val editorAdapter = EditorTabPainterAdapter() + private val islandsAdapter = IslandsTabPainter() + + override val tabPainter: JBTabPainter + get() { + return if (isEnabled) islandsAdapter else editorAdapter.tabPainter + } override fun paintBackground(label: TabLabel, g: Graphics, tabs: JBTabsImpl) { + if (!isEnabled) { + editorAdapter.paintBackground(label, g, tabs) + return + } + val info = label.info val selected = info == tabs.selectedInfo val active = tabs.isActiveTabs(info) @@ -36,7 +48,7 @@ internal class ManyIslandsTabPainterAdapter : TabPainterAdapter { val accentedRect = Rectangle(rect.x, rect.y, rect.width, rect.height) JBInsets.removeFrom(accentedRect, JBInsets(5, 3, 5, 3)) - (tabPainter as ManyIslandsTabPainter).paintTab(g2, accentedRect, info.tabColor, active, hovered, selected) + (tabPainter as IslandsTabPainter).paintTab(g2, accentedRect, info.tabColor, active, hovered, selected) } finally { g2.dispose() @@ -44,7 +56,7 @@ internal class ManyIslandsTabPainterAdapter : TabPainterAdapter { } } -private class ManyIslandsTabTheme : TabTheme { +private class IslandsTabTheme : TabTheme { override val background: Color get() = JBUI.CurrentTheme.EditorTabs.background() @@ -74,8 +86,8 @@ private class ManyIslandsTabTheme : TabTheme { get() = JBColor.namedColor("EditorTabs.underlinedTabInactiveForeground", JBColor(0x000000, 0xFFFFFF)) } -private class ManyIslandsTabPainter : JBTabPainter { - private val myTheme = ManyIslandsTabTheme() +private class IslandsTabPainter : JBTabPainter { + private val myTheme = IslandsTabTheme() override fun getTabTheme(): TabTheme = myTheme diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsUICustomization.kt b/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsUICustomization.kt index b14036def094..dddb9257c172 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsUICustomization.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/islands/IslandsUICustomization.kt @@ -2,6 +2,7 @@ package com.intellij.openapi.application.impl.islands import com.intellij.ide.ui.LafManagerListener +import com.intellij.ide.ui.UISettings import com.intellij.openapi.actionSystem.ex.ActionButtonLook import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.impl.InternalUICustomization @@ -13,16 +14,20 @@ import com.intellij.openapi.ui.Splittable import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.wm.IdeFrame import com.intellij.openapi.wm.IdeGlassPane +import com.intellij.openapi.wm.ToolWindowManager +import com.intellij.openapi.wm.WindowManager +import com.intellij.openapi.wm.ex.ToolWindowManagerEx import com.intellij.openapi.wm.impl.IdeBackgroundUtil import com.intellij.openapi.wm.impl.IdeGlassPaneImpl import com.intellij.openapi.wm.impl.SquareStripeButtonLook +import com.intellij.openapi.wm.impl.ToolWindowImpl import com.intellij.toolWindow.ToolWindowButtonManager import com.intellij.toolWindow.ToolWindowPaneNewButtonManager import com.intellij.toolWindow.xNext.island.XNextIslandHolder import com.intellij.ui.ClientProperty import com.intellij.ui.ExperimentalUI import com.intellij.ui.JBColor -import com.intellij.ui.tabs.impl.TabPainterAdapter +import com.intellij.ui.tabs.impl.JBEditorTabs import com.intellij.util.ui.JBSwingUtilities import com.intellij.util.ui.JBUI import com.intellij.util.ui.UIUtil @@ -30,31 +35,60 @@ import java.awt.* import java.awt.event.AWTEventListener import java.awt.event.HierarchyEvent import javax.swing.JComponent +import javax.swing.border.Border internal class IslandsUICustomization : InternalUICustomization() { private val isIslandsAvailable = !Registry.`is`("llm.riderNext.enabled", false) && ExperimentalUI.isNewUI() + private var isManyIslandEnabledCache: Boolean? = null + private val isManyIslandEnabled: Boolean get() { - return isIslandsAvailable && JBUI.getInt("Islands", 0) == 1 + var value = isManyIslandEnabledCache + if (value == null) { + value = isIslandsAvailable && JBUI.getInt("Islands", 0) == 1 + isManyIslandEnabledCache = value + } + return value } - private val isIslandsGradientEnabled: Boolean = Registry.`is`("idea.islands.gradient.enabled", true) + private var isIslandsGradientEnabledCache: Boolean? = null + + private val isIslandsGradientEnabled: Boolean + get() { + var value = isIslandsGradientEnabledCache + if (value == null) { + value = Registry.`is`("idea.islands.gradient.enabled", true) && UISettings.getInstance().differentiateProjects + isIslandsGradientEnabledCache = value + } + return value + } + + override fun updateBackgroundPainter() { + isIslandsGradientEnabledCache = null + } override val isProjectCustomDecorationGradientPaint: Boolean = !isManyIslandEnabled || !isIslandsGradientEnabled override val shouldPaintEditorFadeout: Boolean = !isManyIslandEnabled - private val toolWindowDecorator = object : ToolWindowUIDecorator() { - override fun decorateAndReturnHolder(divider: JComponent, child: JComponent): JComponent { + override val toolWindowUIDecorator: ToolWindowUIDecorator = object : ToolWindowUIDecorator() { + override fun decorateAndReturnHolder(divider: JComponent, child: JComponent, originalBorderBuilder: () -> Border): JComponent { return XNextIslandHolder().apply { layout = BorderLayout() - background = JBUI.CurrentTheme.ToolWindow.background() add(divider, BorderLayout.NORTH) add(child, BorderLayout.CENTER) - IslandsRoundedBorder.createToolWindowBorder(this) - child.putClientProperty(IdeBackgroundUtil.NO_BACKGROUND, true) + putClientProperty("originalBorderBuilder", originalBorderBuilder) + + if (isManyIslandEnabled) { + background = JBUI.CurrentTheme.ToolWindow.background() + IslandsRoundedBorder.createToolWindowBorder(this) + child.putClientProperty(IdeBackgroundUtil.NO_BACKGROUND, true) + } + else { + border = originalBorderBuilder() + } } } } @@ -77,27 +111,160 @@ internal class IslandsUICustomization : InternalUICustomization() { Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.HIERARCHY_EVENT_MASK) } + var oldManyIsland = isManyIslandEnabled + val connection = ApplicationManager.getApplication().messageBus.connect() connection.subscribe(LafManagerListener.TOPIC, LafManagerListener { val toolkit = Toolkit.getDefaultToolkit() toolkit.removeAWTEventListener(awtListener) + isManyIslandEnabledCache = null - if (isManyIslandEnabled && JBColor.isBright()) { + val newManyIsland = isManyIslandEnabled + + if (newManyIsland && JBColor.isBright()) { toolkit.addAWTEventListener(awtListener, AWTEvent.HIERARCHY_EVENT_MASK) } + + if (oldManyIsland == newManyIsland) { + return@LafManagerListener + } + if (newManyIsland) { + enableManyIslands() + } + else { + disableManyIslands() + } + + oldManyIsland = newManyIsland }) } - private val tabPainterAdapter = ManyIslandsTabPainterAdapter() + private fun enableManyIslands() { + editorTabPainterAdapter.isEnabled = true - override val toolWindowUIDecorator: ToolWindowUIDecorator - get() { - if (isManyIslandEnabled) { - return toolWindowDecorator + // XXX: dialogs + + for (frame in WindowManager.getInstance().allProjectFrames) { + val toolwindows = mutableSetOf() + + UIUtil.forEachComponentInHierarchy(frame.component) { + when (it) { + is XNextIslandHolder -> { + setToolWindowManyBorder(it) + + val id = it.getClientProperty("ToolWindow.ID") + if (id is String) { + toolwindows.add(id) + } + } + is EditorsSplitters -> { + IslandsRoundedBorder.createEditorBorder(it, editorTabPainterAdapter) + clearParentNoBackground(it) + } + is JBEditorTabs -> { + if (it.parent is EditorsSplitters) { + ClientProperty.putRecursive(it, IdeBackgroundUtil.NO_BACKGROUND, true) + } + } + is ManyIslandDivider -> { + it.configure(true) + } + } + } + + val project = frame.project + if (project != null) { + val manager = ToolWindowManager.getInstance(project) as ToolWindowManagerEx + for (toolwindow in manager.toolWindows) { + if (!toolwindows.contains(toolwindow.id) && toolwindow is ToolWindowImpl) { + toolwindow.getNullableDecorator()?.also { + UIUtil.findComponentOfType(it, XNextIslandHolder::class.java)?.also { holder -> + setToolWindowManyBorder(holder) + } + } + } + } } - return super.toolWindowUIDecorator } + } + + private fun disableManyIslands() { + editorTabPainterAdapter.isEnabled = false + + // XXX: dialogs + + for (frame in WindowManager.getInstance().allProjectFrames) { + val toolwindows = mutableSetOf() + + UIUtil.forEachComponentInHierarchy(frame.component) { + if (it is JComponent) { + ClientProperty.removeRecursive(it, IdeBackgroundUtil.NO_BACKGROUND) + } + + when (it) { + is XNextIslandHolder -> { + setOriginalToolWindowBorder(it) + + val id = it.getClientProperty("ToolWindow.ID") + if (id is String) { + toolwindows.add(id) + } + } + is EditorsSplitters -> { + it.border = null + } + is ManyIslandDivider -> { + it.configure(false) + } + } + } + + val project = frame.project + if (project != null) { + val manager = ToolWindowManager.getInstance(project) as ToolWindowManagerEx + for (toolwindow in manager.toolWindows) { + if (!toolwindows.contains(toolwindow.id) && toolwindow is ToolWindowImpl) { + toolwindow.getNullableDecorator()?.also { + UIUtil.findComponentOfType(it, XNextIslandHolder::class.java)?.also { holder -> + setOriginalToolWindowBorder(holder) + } + } + } + } + } + } + } + + private fun setOriginalToolWindowBorder(holder: XNextIslandHolder) { + val builder = holder.getClientProperty("originalBorderBuilder") + if (builder is Function0<*>) { + val border = builder() + if (border is Border) { + holder.setSuperBorder(border) + } + } + holder.background = JBColor.PanelBackground + } + + private fun setToolWindowManyBorder(holder: XNextIslandHolder) { + holder.background = JBUI.CurrentTheme.ToolWindow.background() + IslandsRoundedBorder.createToolWindowBorder(holder) + clearParentNoBackground(holder) + + for (child in holder.components) { + ClientProperty.putRecursive(child as JComponent, IdeBackgroundUtil.NO_BACKGROUND, true) + } + } + + private fun clearParentNoBackground(component: JComponent) { + var nextComponent: JComponent? = component + + while (nextComponent != null && ClientProperty.get(nextComponent, IdeBackgroundUtil.NO_BACKGROUND) != null) { + ClientProperty.removeRecursive(nextComponent, IdeBackgroundUtil.NO_BACKGROUND) + nextComponent = nextComponent.parent as JComponent? + } + } override fun configureToolWindowPane(toolWindowPaneParent: JComponent, buttonManager: ToolWindowButtonManager) { if (isManyIslandEnabled && buttonManager is ToolWindowPaneNewButtonManager) { @@ -129,15 +296,9 @@ internal class IslandsUICustomization : InternalUICustomization() { } override fun createCustomDivider(isVertical: Boolean, splitter: Splittable): Divider? { - if (isManyIslandEnabled) { - return object : OnePixelDivider(isVertical, splitter) { - override fun paint(g: Graphics) { - } - }.also { - it.putClientProperty("DividerWidth", 0) - } + return ManyIslandDivider(isVertical, splitter).also { + it.configure(isManyIslandEnabled) } - return null } override fun configureRendererComponent(component: JComponent) { @@ -154,34 +315,34 @@ internal class IslandsUICustomization : InternalUICustomization() { override fun configureEditorsSplitters(component: EditorsSplitters) { if (isManyIslandEnabled) { - IslandsRoundedBorder.createEditorBorder(component, tabPainterAdapter) + IslandsRoundedBorder.createEditorBorder(component, editorTabPainterAdapter) } } override fun paintBeforeEditorEmptyText(component: JComponent, graphics: Graphics) { if (isManyIslandEnabled) { - IslandsRoundedBorder.paintBeforeEditorEmptyText(component, graphics, tabPainterAdapter) + IslandsRoundedBorder.paintBeforeEditorEmptyText(component, graphics, editorTabPainterAdapter) } } - override val editorTabPainterAdapter: TabPainterAdapter - get() { - if (isManyIslandEnabled) { - return tabPainterAdapter - } - return super.editorTabPainterAdapter - } + override val editorTabPainterAdapter: IslandsTabPainterAdapter = IslandsTabPainterAdapter(isManyIslandEnabled) + + private fun getMainBackgroundColor(): Color { + return JBColor.namedColor("MainWindow.background", JBColor.PanelBackground) + } override fun getCustomMainBackgroundColor(): Color? { if (isManyIslandEnabled) { - return JBColor.namedColor("MainWindow.background", JBColor.PanelBackground) + return getMainBackgroundColor() } - return super.getCustomMainBackgroundColor() + return null } override fun attachIdeFrameBackgroundPainter(frame: IdeFrame, glassPane: IdeGlassPane) { - if (isManyIslandEnabled && isIslandsGradientEnabled && glassPane is IdeGlassPaneImpl) { - glassPane.addFallbackBackgroundPainter(IslandsGradientPainter(frame, getCustomMainBackgroundColor()!!)) + if (glassPane is IdeGlassPaneImpl) { + glassPane.addFallbackBackgroundPainter(IslandsGradientPainter(frame, getMainBackgroundColor()) { + isManyIslandEnabled && isIslandsGradientEnabled + }) } } @@ -209,4 +370,25 @@ internal class IslandsUICustomization : InternalUICustomization() { } return graphics } +} + +private class ManyIslandDivider(isVertical: Boolean, splitter: Splittable) : OnePixelDivider(isVertical, splitter) { + private var doPaint = true + + fun configure(manyIsland: Boolean) { + doPaint = !manyIsland + + if (manyIsland) { + putClientProperty("DividerWidth", 0) + } + else { + putClientProperty("DividerWidth", null) + } + } + + override fun paint(g: Graphics) { + if (doPaint) { + super.paint(g) + } + } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt index d55cb3ed14f7..6388a8ce2281 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt @@ -486,6 +486,8 @@ internal class ToolWindowImpl( toolWindowManager.stretchHeight(this, value) } + internal fun getNullableDecorator() = decorator + override fun getDecorator(): InternalDecoratorImpl = decorator!! override fun setAdditionalGearActions(value: ActionGroup?) { diff --git a/platform/platform-impl/src/com/intellij/toolWindow/InternalDecoratorImpl.kt b/platform/platform-impl/src/com/intellij/toolWindow/InternalDecoratorImpl.kt index 1ba6f6212e7f..56d255aef616 100644 --- a/platform/platform-impl/src/com/intellij/toolWindow/InternalDecoratorImpl.kt +++ b/platform/platform-impl/src/com/intellij/toolWindow/InternalDecoratorImpl.kt @@ -279,8 +279,12 @@ class InternalDecoratorImpl internal constructor( Mode.SINGLE, Mode.CELL -> { layout = BorderLayout() - InternalUICustomization.getInstance()?.toolWindowUIDecorator?.decorateAndReturnHolder(dividerAndHeader, myDecoratorChild)?.let { + val decorator = InternalUICustomization.getInstance()?.toolWindowUIDecorator + ?.decorateAndReturnHolder(dividerAndHeader, myDecoratorChild) { InnerPanelBorder(toolWindow) } + + decorator?.let { add(it, BorderLayout.CENTER) + putClientProperty("ToolWindow.ID", toolWindowId) } ?: run { add(dividerAndHeader, BorderLayout.NORTH) add(myDecoratorChild, BorderLayout.CENTER) diff --git a/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowPane.kt b/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowPane.kt index 6598968d1f0a..43a7e52c0e96 100644 --- a/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowPane.kt +++ b/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowPane.kt @@ -617,7 +617,7 @@ class ToolWindowPane private constructor( } override fun createDivider(): Divider { - return InternalUICustomization.getInstance()?.createCustomDivider(isVisible, this) + return InternalUICustomization.getInstance()?.createCustomDivider(isVertical, this) ?: super.createDivider().also { it.background = JBUI.CurrentTheme.ToolWindow.mainBorderColor() } } diff --git a/platform/platform-impl/src/com/intellij/toolWindow/xNext/island/XNextIslandHolder.kt b/platform/platform-impl/src/com/intellij/toolWindow/xNext/island/XNextIslandHolder.kt index c3891af3d3fe..fda09ef2997f 100644 --- a/platform/platform-impl/src/com/intellij/toolWindow/xNext/island/XNextIslandHolder.kt +++ b/platform/platform-impl/src/com/intellij/toolWindow/xNext/island/XNextIslandHolder.kt @@ -48,6 +48,10 @@ class XNextIslandHolder : JPanel() { super.setBorder(border) } + fun setSuperBorder(border: Border?) { + super.setBorder(border) + } + override fun isOpaque(): Boolean { return true } diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 5e9a1d80737b..17a8962c2fd0 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -690,8 +690,8 @@ - - + + diff --git a/platform/util/ui/src/com/intellij/ui/ClientProperty.java b/platform/util/ui/src/com/intellij/ui/ClientProperty.java index cdf37c18d62a..5ef12a927229 100644 --- a/platform/util/ui/src/com/intellij/ui/ClientProperty.java +++ b/platform/util/ui/src/com/intellij/ui/ClientProperty.java @@ -116,6 +116,24 @@ public final class ClientProperty { } } + @ApiStatus.Internal + public static void removeRecursive(@NotNull JComponent component, @NotNull Key key) { + Map, ContainerListener> listeners = get(component, RECURSIVE_LISTENERS); + + if (listeners != null) { + ContainerListener existingListener = listeners.remove(key); + if (existingListener != null) { + component.removeContainerListener(existingListener); + + if (listeners.isEmpty()) { + put(component, RECURSIVE_LISTENERS, null); + } + } + } + + put(component, key, null); + } + @Contract("null -> null") private static @Nullable JComponent getPropertiesHolder(@Nullable Component component) { if (component instanceof JComponent) return (JComponent)component;