From 13a231490d091f7547ee6d75721917d5202cf4f4 Mon Sep 17 00:00:00 2001 From: Kirill Grouchnikov Date: Sun, 19 Jan 2025 14:24:01 -0500 Subject: [PATCH] Tonal tabbed panes For #400 --- .../theming/internal/blade/BladeUtils.java | 114 +++++ .../internal/ui/RadianceTabbedPaneUI.java | 479 +++++++++++++----- .../utils/RadianceColorSchemeUtilities.java | 46 +- .../internal/utils/RadianceCoreUtilities.java | 43 +- 4 files changed, 535 insertions(+), 147 deletions(-) diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/blade/BladeUtils.java b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/blade/BladeUtils.java index ca273745a..9d1e9b3d0 100644 --- a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/blade/BladeUtils.java +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/blade/BladeUtils.java @@ -822,4 +822,118 @@ public static void populateColorScheme( bladeColorScheme.displayName = nameBuilder.toString(); } + + + public static void populateColorTokens( + BladeContainerColorTokens bladeContainerTokens, JTabbedPane tabbedPane, int tabIndex, + StateTransitionTracker.ModelStateInfo modelStateInfo, ComponentState currState, + RadianceThemingSlices.ContainerColorTokensAssociationKind associationKind) { + if (!SwingUtilities.isEventDispatchThread()) { + UiThreadingViolationException uiThreadingViolationError = new UiThreadingViolationException( + "Color scheme population must be done on Event Dispatch Thread"); + uiThreadingViolationError.printStackTrace(System.err); + throw uiThreadingViolationError; + } + + StringBuilder nameBuilder = new StringBuilder(); + ContainerColorTokens currColorTokens = RadianceColorSchemeUtilities.getContainerTokens( + tabbedPane, tabIndex, associationKind, currState); + Color containerSurfaceLowest = currColorTokens.getContainerSurfaceLowest(); + Color containerSurfaceLow = currColorTokens.getContainerSurfaceLow(); + Color containerSurface = currColorTokens.getContainerSurface(); + Color containerSurfaceHigh = currColorTokens.getContainerSurfaceHigh(); + Color containerSurfaceHighest = currColorTokens.getContainerSurfaceHighest(); + Color onContainer = currColorTokens.getOnContainer(); + Color onContainerVariant = currColorTokens.getOnContainerVariant(); + Color containerOutline = currColorTokens.getContainerOutline(); + Color containerOutlineVariant = currColorTokens.getContainerOutlineVariant(); + float containerDisabledAlpha = currColorTokens.getContainerSurfaceDisabledAlpha(); + float onContainerDisabledAlpha = currColorTokens.getOnContainerDisabledAlpha(); + float containerOutlineDisabledAlpha = currColorTokens.getContainerOutlineDisabledAlpha(); + Color inverseContainerSurface = currColorTokens.getInverseContainerSurface(); + Color inverseOnContainer = currColorTokens.getInverseOnContainer(); + Color inverseContainerOutline = currColorTokens.getInverseContainerOutline(); + + nameBuilder.append(currColorTokens.hashCode()); + + boolean isDark = currColorTokens.isDark(); + + Map activeStates = + (modelStateInfo == null) ? null : modelStateInfo.getStateContributionMap(); + + if (!currState.isDisabled() && (activeStates != null) && (activeStates.size() > 1)) { + for (Map.Entry activeEntry : activeStates.entrySet()) { + ComponentState activeState = activeEntry.getKey(); + if (activeState == currState) { + // Already accounted for the currently active state + continue; + } + float amount = activeEntry.getValue().getContribution(); + if (amount == 0.0f) { + // Skip a zero-amount contribution + continue; + } + // Get the color scheme that matches the contribution state + ContainerColorTokens contributionColorTokens = + RadianceColorSchemeUtilities.getContainerTokens( + tabbedPane, tabIndex, associationKind, activeState); + + // And interpolate the colors + containerSurfaceLowest = RadianceColorUtilities.getInterpolatedColor(containerSurfaceLowest, + contributionColorTokens.getContainerSurfaceLowest(), 1.0f - amount); + containerSurfaceLow = RadianceColorUtilities.getInterpolatedColor(containerSurfaceLow, + contributionColorTokens.getContainerSurfaceLow(), 1.0f - amount); + containerSurface = RadianceColorUtilities.getInterpolatedColor(containerSurface, + contributionColorTokens.getContainerSurface(), 1.0f - amount); + containerSurfaceHigh = RadianceColorUtilities.getInterpolatedColor(containerSurfaceHigh, + contributionColorTokens.getContainerSurfaceHigh(), 1.0f - amount); + containerSurfaceHighest = RadianceColorUtilities.getInterpolatedColor(containerSurfaceHighest, + contributionColorTokens.getContainerSurfaceHighest(), 1.0f - amount); + onContainer = RadianceColorUtilities.getInterpolatedColor(onContainer, + contributionColorTokens.getOnContainer(), 1.0f - amount); + onContainerVariant = RadianceColorUtilities.getInterpolatedColor(onContainerVariant, + contributionColorTokens.getOnContainerVariant(), 1.0f - amount); + containerOutline = RadianceColorUtilities.getInterpolatedColor(containerOutline, + contributionColorTokens.getContainerOutline(), 1.0f - amount); + containerOutlineVariant = RadianceColorUtilities.getInterpolatedColor(containerOutlineVariant, + contributionColorTokens.getContainerOutlineVariant(), 1.0f - amount); + containerDisabledAlpha = (1.0f - amount) * containerDisabledAlpha + + amount * contributionColorTokens.getContainerSurfaceDisabledAlpha(); + onContainerDisabledAlpha = (1.0f - amount) * onContainerDisabledAlpha + + amount * contributionColorTokens.getOnContainerDisabledAlpha(); + containerOutlineDisabledAlpha = (1.0f - amount) * containerOutlineDisabledAlpha + + amount * contributionColorTokens.getContainerOutlineDisabledAlpha(); + inverseContainerSurface = RadianceColorUtilities.getInterpolatedColor(inverseContainerSurface, + contributionColorTokens.getInverseContainerSurface(), 1.0f - amount); + inverseOnContainer = RadianceColorUtilities.getInterpolatedColor(inverseOnContainer, + contributionColorTokens.getInverseOnContainer(), 1.0f - amount); + inverseContainerOutline = RadianceColorUtilities.getInterpolatedColor(inverseContainerOutline, + contributionColorTokens.getInverseContainerOutline(), 1.0f - amount); + + nameBuilder.append(", [").append(contributionColorTokens.hashCode()).append(":") + .append(amount).append("]"); + isDark = isDark && contributionColorTokens.isDark(); + } + } + + // Update the mutable color tokens with the interpolated colors + bladeContainerTokens.containerSurfaceLowest = containerSurfaceLowest; + bladeContainerTokens.containerSurfaceLow = containerSurfaceLow; + bladeContainerTokens.containerSurface = containerSurface; + bladeContainerTokens.containerSurfaceHigh = containerSurfaceHigh; + bladeContainerTokens.containerSurfaceHighest = containerSurfaceHighest; + bladeContainerTokens.onContainer = onContainer; + bladeContainerTokens.onContainerVariant = onContainerVariant; + bladeContainerTokens.containerOutline = containerOutline; + bladeContainerTokens.containerOutlineVariant = containerOutlineVariant; + bladeContainerTokens.containerDisabledAlpha = containerDisabledAlpha; + bladeContainerTokens.onContainerDisabledAlpha = onContainerDisabledAlpha; + bladeContainerTokens.containerOutlineDisabledAlpha = containerOutlineDisabledAlpha; + bladeContainerTokens.inverseContainerSurface = inverseContainerSurface; + bladeContainerTokens.inverseOnContainer = inverseOnContainer; + bladeContainerTokens.inverseContainerOutline = inverseContainerOutline; + + bladeContainerTokens.combinedName = nameBuilder.toString(); + bladeContainerTokens.isDark = isDark; + } } diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/ui/RadianceTabbedPaneUI.java b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/ui/RadianceTabbedPaneUI.java index ba31154e8..f3fc72276 100644 --- a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/ui/RadianceTabbedPaneUI.java +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/ui/RadianceTabbedPaneUI.java @@ -34,13 +34,12 @@ import org.pushingpixels.radiance.animation.api.Timeline.TimelineState; import org.pushingpixels.radiance.animation.api.swing.EventDispatchThreadTimelineCallbackAdapter; import org.pushingpixels.radiance.common.api.RadianceCommonCortex; -import org.pushingpixels.radiance.theming.api.ComponentState; -import org.pushingpixels.radiance.theming.api.RadianceThemingCortex; -import org.pushingpixels.radiance.theming.api.RadianceThemingSlices; -import org.pushingpixels.radiance.theming.api.RadianceThemingWidget; +import org.pushingpixels.radiance.theming.api.*; import org.pushingpixels.radiance.theming.api.colorscheme.RadianceColorScheme; import org.pushingpixels.radiance.theming.api.painter.border.RadianceBorderPainter; import org.pushingpixels.radiance.theming.api.painter.fill.RadianceFillPainter; +import org.pushingpixels.radiance.theming.api.palette.ContainerColorTokens; +import org.pushingpixels.radiance.theming.api.palette.TonalSkin; import org.pushingpixels.radiance.theming.api.tabbed.*; import org.pushingpixels.radiance.theming.internal.AnimationConfigurationManager; import org.pushingpixels.radiance.theming.internal.RadianceSynapse; @@ -63,8 +62,8 @@ import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.beans.PropertyChangeListener; -import java.util.List; import java.util.*; +import java.util.List; /** * UI for tabbed panes in Radiance look and feel. @@ -120,7 +119,7 @@ public static ComponentUI createUI(JComponent comp) { private BladeColorScheme mutableFillColorScheme = new BladeColorScheme(); private BladeColorScheme mutableBorderColorScheme = new BladeColorScheme(); private BladeColorScheme mutableMarkColorScheme = new BladeColorScheme(); - + private BladeContainerColorTokens mutableColorTokens = new BladeContainerColorTokens(); /** * Tracks changes to the tabbed pane contents. Each tab component is tracked for changes on the @@ -483,9 +482,9 @@ public void mouseReleased(final MouseEvent e) { .getTabCloseCallback(RadianceTabbedPaneUI.this.tabPane, tabIndex); - RadianceThemingSlices.TabCloseKind tabCloseKind = (closeCallback == null) ? RadianceThemingSlices.TabCloseKind.THIS - : closeCallback.onCloseButtonClick( - RadianceTabbedPaneUI.this.tabPane, tabIndex, e); + RadianceThemingSlices.TabCloseKind tabCloseKind = (closeCallback == null) + ? RadianceThemingSlices.TabCloseKind.THIS + : closeCallback.onCloseButtonClick(RadianceTabbedPaneUI.this.tabPane, tabIndex, e); RadianceTabbedPaneUI.this.tryCloseTabs(tabIndex, tabCloseKind); } @@ -655,8 +654,8 @@ protected void uninstallComponents() { } private static void paintTabBackgroundAt1X(Graphics2D graphics1X, - JTabbedPane tabPane, int tabIndex, double scaleFactor, int width, int height, - RadianceColorScheme fillScheme, RadianceColorScheme borderScheme, Color tabColor) { + JTabbedPane tabPane, int tabIndex, double scaleFactor, int width, int height, + RadianceColorScheme fillScheme, RadianceColorScheme borderScheme, Color tabColor) { RadianceFillPainter fillPainter = RadianceCoreUtilities.getFillPainter(tabPane); RadianceBorderPainter borderPainter = RadianceCoreUtilities.getBorderPainter(tabPane); @@ -665,12 +664,12 @@ private static void paintTabBackgroundAt1X(Graphics2D graphics1X, // Always use slightly rounded corners on tabs float cornerRadius = (float) scaleFactor * RadianceSizeUtils - .getClassicButtonCornerRadius(RadianceSizeUtils.getComponentFontSize(tabPane)); + .getClassicButtonCornerRadius(RadianceSizeUtils.getComponentFontSize(tabPane)); width -= 1; Shape contour = RadianceOutlineUtilities.getBaseOutline( - tabPane.getComponentOrientation(), - width, height + dy, cornerRadius, straightSides, 1.0f); + tabPane.getComponentOrientation(), + width, height + dy, cornerRadius, straightSides, 1.0f); graphics1X.setColor(tabColor); graphics1X.fill(contour); @@ -681,66 +680,145 @@ private static void paintTabBackgroundAt1X(Graphics2D graphics1X, clipped.dispose(); Shape contourInner = borderPainter.isPaintingInnerContour() ? - RadianceOutlineUtilities.getBaseOutline( - tabPane.getComponentOrientation(), - width, height + dy, cornerRadius - 1.0f, straightSides, 2.0f) - : null; + RadianceOutlineUtilities.getBaseOutline( + tabPane.getComponentOrientation(), + width, height + dy, cornerRadius - 1.0f, straightSides, 2.0f) + : null; borderPainter.paintBorder(graphics1X, tabPane, width, height + dy, contour, contourInner, - borderScheme); + borderScheme); RadianceColorScheme blendedBorderScheme = RadianceColorSchemeUtilities.getColorScheme( - tabPane, tabIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, - ComponentState.SELECTED); + tabPane, tabIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, + ComponentState.SELECTED); Color lineColor = borderPainter.getRepresentativeColor(blendedBorderScheme); Color lineColorFullTransparency = RadianceColorUtilities.getAlphaColor(lineColor, 0); graphics1X.setPaint(new LinearGradientPaint(0.0f, 0.0f, 0.0f, height, - new float[]{0.0f, 0.5f, 1.0f}, - new Color[]{lineColorFullTransparency, lineColorFullTransparency, lineColor})); + new float[]{0.0f, 0.5f, 1.0f}, + new Color[]{lineColorFullTransparency, lineColorFullTransparency, lineColor})); + graphics1X.draw(contour); + } + + private static void paintTabBackgroundAt1X(Graphics2D graphics1X, + JTabbedPane tabPane, int tabIndex, double scaleFactor, int width, int height, + ContainerColorTokens colorTokens, Color tabColor) { + RadianceFillPainter fillPainter = RadianceCoreUtilities.getFillPainter(tabPane); + RadianceBorderPainter borderPainter = RadianceCoreUtilities.getBorderPainter(tabPane); + + int dy = 3; + Set straightSides = EnumSet.of(RadianceThemingSlices.Side.BOTTOM); + + // Always use slightly rounded corners on tabs + float cornerRadius = (float) scaleFactor * RadianceSizeUtils + .getClassicButtonCornerRadius(RadianceSizeUtils.getComponentFontSize(tabPane)); + width -= 1; + + Shape contour = RadianceOutlineUtilities.getBaseOutline( + tabPane.getComponentOrientation(), + width, height + dy, cornerRadius, straightSides, 1.0f); + + graphics1X.setColor(tabColor); + graphics1X.fill(contour); + Graphics2D clipped = (Graphics2D) graphics1X.create(); + clipped.clipRect(0, 0, width, (int) (0.2f * height)); + clipped.setColor(colorTokens.getContainerSurface()); + clipped.fill(contour); + clipped.dispose(); + + Shape contourInner = borderPainter.isPaintingInnerContour() ? + RadianceOutlineUtilities.getBaseOutline( + tabPane.getComponentOrientation(), + width, height + dy, cornerRadius - 1.0f, straightSides, 2.0f) + : null; + + borderPainter.paintBorder(graphics1X, tabPane, width, height + dy, contour, contourInner, + colorTokens); + + ContainerColorTokens blendedContainerTokens = RadianceColorSchemeUtilities.getContainerTokens( + tabPane, tabIndex, RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, + ComponentState.SELECTED); + Color lineColor = blendedContainerTokens.getContainerOutline(); + Color lineColorFullTransparency = RadianceColorUtilities.getAlphaColor(lineColor, 0); + graphics1X.setPaint(new LinearGradientPaint(0.0f, 0.0f, 0.0f, height, + new float[]{0.0f, 0.5f, 1.0f}, + new Color[]{lineColorFullTransparency, lineColorFullTransparency, lineColor})); graphics1X.draw(contour); } private void paintRotationAwareTabBackground(Graphics2D g, JTabbedPane tabPane, int tabIndex, - int width, int height, int tabPlacement, - RadianceColorScheme colorScheme, RadianceColorScheme borderScheme) { + int width, int height, int tabPlacement, + RadianceColorScheme colorScheme, RadianceColorScheme borderScheme) { Graphics2D graphics = (Graphics2D) g.create(); // Important - do not set KEY_STROKE_CONTROL to VALUE_STROKE_PURE, as that instructs AWT // to not normalize coordinates to paint at full pixels, and will result in blurry // outlines. graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); + RenderingHints.VALUE_ANTIALIAS_ON); RadianceCommonCortex.paintAtScale1x(graphics, 0, 0, width, height, - (graphics1X, x, y, scaledWidth, scaledHeight, scaleFactor) -> { - Component compForBackground = tabPane.getTabComponentAt(tabIndex); - if (compForBackground == null) - compForBackground = tabPane.getComponentAt(tabIndex); - if (compForBackground == null) - compForBackground = tabPane; - Color tabColor = compForBackground.getBackground(); - if (tabColor instanceof UIResource) { - // special handling of tabs placed in decoration areas - tabColor = RadianceColorUtilities.getBackgroundFillColor(compForBackground); - } + (graphics1X, x, y, scaledWidth, scaledHeight, scaleFactor) -> { + Component compForBackground = tabPane.getTabComponentAt(tabIndex); + if (compForBackground == null) + compForBackground = tabPane.getComponentAt(tabIndex); + if (compForBackground == null) + compForBackground = tabPane; + Color tabColor = compForBackground.getBackground(); + if (tabColor instanceof UIResource) { + // special handling of tabs placed in decoration areas + tabColor = RadianceColorUtilities.getBackgroundFillColor(compForBackground); + } - if (tabPlacement == BOTTOM) { - AffineTransform transform = AffineTransform.getTranslateInstance(scaledWidth, scaledHeight); - transform.rotate(Math.PI); - graphics1X.transform(transform); - } + if (tabPlacement == BOTTOM) { + AffineTransform transform = AffineTransform.getTranslateInstance(scaledWidth, scaledHeight); + transform.rotate(Math.PI); + graphics1X.transform(transform); + } - paintTabBackgroundAt1X(graphics1X, tabPane, tabIndex, scaleFactor, - scaledWidth, scaledHeight, - colorScheme, borderScheme, tabColor); - }); + paintTabBackgroundAt1X(graphics1X, tabPane, tabIndex, scaleFactor, + scaledWidth, scaledHeight, + colorScheme, borderScheme, tabColor); + }); + } + + private void paintRotationAwareTabBackground(Graphics2D g, JTabbedPane tabPane, int tabIndex, + int width, int height, int tabPlacement, ContainerColorTokens colorTokens) { + + Graphics2D graphics = (Graphics2D) g.create(); + // Important - do not set KEY_STROKE_CONTROL to VALUE_STROKE_PURE, as that instructs AWT + // to not normalize coordinates to paint at full pixels, and will result in blurry + // outlines. + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + RadianceCommonCortex.paintAtScale1x(graphics, 0, 0, width, height, + (graphics1X, x, y, scaledWidth, scaledHeight, scaleFactor) -> { + Component compForBackground = tabPane.getTabComponentAt(tabIndex); + if (compForBackground == null) + compForBackground = tabPane.getComponentAt(tabIndex); + if (compForBackground == null) + compForBackground = tabPane; + Color tabColor = compForBackground.getBackground(); + if (tabColor instanceof UIResource) { + // special handling of tabs placed in decoration areas + tabColor = RadianceColorUtilities.getBackgroundFillColor(compForBackground); + } + + if (tabPlacement == BOTTOM) { + AffineTransform transform = AffineTransform.getTranslateInstance(scaledWidth, scaledHeight); + transform.rotate(Math.PI); + graphics1X.transform(transform); + } + + paintTabBackgroundAt1X(graphics1X, tabPane, tabIndex, scaleFactor, + scaledWidth, scaledHeight, colorTokens, tabColor); + }); } /** * Retrieves the image of the close button. */ private void paintCloseButtonImage(Graphics2D g, JTabbedPane tabPane, int width, int height, - boolean toPaintBorder, RadianceColorScheme fillScheme, - RadianceColorScheme markScheme) { + boolean toPaintBorder, RadianceColorScheme fillScheme, + RadianceColorScheme markScheme) { RadianceFillPainter fillPainter = RadianceCoreUtilities.getFillPainter(tabPane); if (fillPainter == null) { return; @@ -751,26 +829,61 @@ private void paintCloseButtonImage(Graphics2D g, JTabbedPane tabPane, int width, // to not normalize coordinates to paint at full pixels, and will result in blurry // outlines. graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); + RenderingHints.VALUE_ANTIALIAS_ON); RadianceCommonCortex.paintAtScale1x(graphics, 0, 0, width, height, - (graphics1X, x, y, scaledWidth, scaledHeight, scaleFactor) -> { - if (toPaintBorder) { - Shape contour = RadianceOutlineUtilities.getBaseOutline( - tabPane.getComponentOrientation(), - scaledWidth, scaledHeight, 1, null); - fillPainter.paintContourBackground(graphics1X, tabPane, - scaledWidth, scaledHeight, contour, - fillScheme); - RadianceBorderPainter borderPainter = - RadianceCoreUtilities.getBorderPainter(tabPane); - borderPainter.paintBorder(graphics1X, tabPane, scaledWidth, scaledHeight, - contour, null, markScheme); - } + (graphics1X, x, y, scaledWidth, scaledHeight, scaleFactor) -> { + if (toPaintBorder) { + Shape contour = RadianceOutlineUtilities.getBaseOutline( + tabPane.getComponentOrientation(), + scaledWidth, scaledHeight, 1, null); + fillPainter.paintContourBackground(graphics1X, tabPane, + scaledWidth, scaledHeight, contour, + fillScheme); + RadianceBorderPainter borderPainter = + RadianceCoreUtilities.getBorderPainter(tabPane); + borderPainter.paintBorder(graphics1X, tabPane, scaledWidth, scaledHeight, + contour, null, markScheme); + } - BladeIconUtils.drawCloseIcon(graphics1X, scaledWidth, - RadianceSizeUtils.getTabCloseButtonStrokeWidth(tabPane), - markScheme); - }); + BladeIconUtils.drawCloseIcon(graphics1X, scaledWidth, + RadianceSizeUtils.getTabCloseButtonStrokeWidth(tabPane), + markScheme); + }); + } + + /** + * Retrieves the image of the close button. + */ + private void paintCloseButtonImage(Graphics2D g, JTabbedPane tabPane, int width, int height, + boolean toPaintBorder, ContainerColorTokens colorTokens) { + RadianceFillPainter fillPainter = RadianceCoreUtilities.getFillPainter(tabPane); + if (fillPainter == null) { + return; + } + + Graphics2D graphics = (Graphics2D) g.create(); + // Important - do not set KEY_STROKE_CONTROL to VALUE_STROKE_PURE, as that instructs AWT + // to not normalize coordinates to paint at full pixels, and will result in blurry + // outlines. + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + RadianceCommonCortex.paintAtScale1x(graphics, 0, 0, width, height, + (graphics1X, x, y, scaledWidth, scaledHeight, scaleFactor) -> { + if (toPaintBorder) { + Shape contour = RadianceOutlineUtilities.getBaseOutline( + tabPane.getComponentOrientation(), + scaledWidth, scaledHeight, 1, null); + fillPainter.paintContourBackground(graphics1X, tabPane, + scaledWidth, scaledHeight, contour, colorTokens); + RadianceBorderPainter borderPainter = + RadianceCoreUtilities.getBorderPainter(tabPane); + borderPainter.paintBorder(graphics1X, tabPane, scaledWidth, scaledHeight, + contour, null, colorTokens); + } + + BladeIconUtils.drawCloseIcon(graphics1X, scaledWidth, + RadianceSizeUtils.getTabCloseButtonStrokeWidth(tabPane), colorTokens); + }); } @Override @@ -779,6 +892,8 @@ protected void paintTabBackground(Graphics g, int tabPlacement, final int tabInd Graphics2D graphics = (Graphics2D) g.create(); graphics.setComposite(WidgetUtilities.getAlphaComposite(this.tabPane, g)); + RadianceSkin skin = RadianceCoreUtilities.getSkin(this.tabPane); + boolean isEnabled = this.tabPane.isEnabledAt(tabIndex); ComponentState currState = this.getTabState(tabIndex, false); StateTransitionTracker.ModelStateInfo modelStateInfo = this.getModelStateInfo(tabIndex); @@ -804,8 +919,15 @@ protected void paintTabBackground(Graphics g, int tabPlacement, final int tabInd } } - finalAlpha *= RadianceColorSchemeUtilities.getAlpha(this.tabPane.getComponentAt(tabIndex), - currState); + if (skin instanceof TonalSkin) { + if (!this.tabPane.isEnabledAt(tabIndex)) { + finalAlpha *= RadianceColorSchemeUtilities.getContainerTokens( + this.tabPane, tabIndex, RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, + currState).getContainerSurfaceDisabledAlpha(); + } + } else { + finalAlpha *= RadianceColorSchemeUtilities.getAlpha(this.tabPane.getComponentAt(tabIndex), currState); + } // check if tab has its content marked as modified Component comp = this.tabPane.getComponentAt(tabIndex); @@ -815,30 +937,41 @@ protected void paintTabBackground(Graphics g, int tabPlacement, final int tabInd graphics.translate(x, y); if (isTabModified && isEnabled && !toMarkModifiedCloseButton) { - BladeUtils.populateModificationAwareColorScheme(mutableFillColorScheme, + if (skin instanceof TonalSkin) { + BladeUtils.populateModificationAwareColorTokens(mutableColorTokens, comp, + this.modifiedTimelines.get(comp).getTimelinePosition()); + paintRotationAwareTabBackground(graphics, this.tabPane, tabIndex, w, h, tabPlacement, + mutableColorTokens); + } else { + BladeUtils.populateModificationAwareColorScheme(mutableFillColorScheme, this.modifiedTimelines.get(comp).getTimelinePosition()); - RadianceColorScheme baseBorderScheme = RadianceColorSchemeUtilities.getColorScheme( - this.tabPane, tabIndex, - RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, currState); + RadianceColorScheme baseBorderScheme = RadianceColorSchemeUtilities.getColorScheme( + this.tabPane, tabIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, + currState); - paintRotationAwareTabBackground(graphics, this.tabPane, - tabIndex, w, h, tabPlacement, + paintRotationAwareTabBackground(graphics, this.tabPane, tabIndex, w, h, tabPlacement, mutableFillColorScheme, baseBorderScheme); + } } else { - // Populate fill and border color schemes based on the current transition state of the button. - // Important - don't do it on pulsating buttons (such as close button of modified frames). - BladeUtils.populateColorScheme(mutableFillColorScheme, this.tabPane, tabIndex, - modelStateInfo, currState, - RadianceThemingSlices.ColorSchemeAssociationKind.TAB, - false); - BladeUtils.populateColorScheme(mutableBorderColorScheme, this.tabPane, tabIndex, - modelStateInfo, currState, - RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, - false); - - paintRotationAwareTabBackground(graphics, this.tabPane, - tabIndex, w, h, tabPlacement, + if (skin instanceof TonalSkin) { + // Populate color tokens based on the current transition state of the button. + // Important - don't do it on pulsating buttons (such as close button of modified frames). + BladeUtils.populateColorTokens(mutableColorTokens, this.tabPane, tabIndex, + modelStateInfo, currState, RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB); + + paintRotationAwareTabBackground(graphics, this.tabPane, tabIndex, w, h, tabPlacement, + mutableColorTokens); + } else { + // Populate fill and border color schemes based on the current transition state of the button. + // Important - don't do it on pulsating buttons (such as close button of modified frames). + BladeUtils.populateColorScheme(mutableFillColorScheme, this.tabPane, tabIndex, + modelStateInfo, currState, RadianceThemingSlices.ColorSchemeAssociationKind.TAB, false); + BladeUtils.populateColorScheme(mutableBorderColorScheme, this.tabPane, tabIndex, + modelStateInfo, currState, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, false); + + paintRotationAwareTabBackground(graphics, this.tabPane, tabIndex, w, h, tabPlacement, mutableFillColorScheme, mutableBorderColorScheme); + } } graphics.translate(-x, -y); @@ -878,29 +1011,40 @@ protected void paintTabBackground(Graphics g, int tabPlacement, final int tabInd graphics.translate(orig.x, orig.y); if (isTabModified && isEnabled && toMarkModifiedCloseButton) { - BladeUtils.populateModificationAwareColorScheme(mutableFillColorScheme, + if (skin instanceof TonalSkin) { + BladeUtils.populateModificationAwareColorTokens(mutableColorTokens, comp, + this.modifiedTimelines.get(comp).getTimelinePosition()); + paintCloseButtonImage(graphics, this.tabPane, orig.width, orig.height, + toPaintCloseBorder, mutableColorTokens); + } else { + BladeUtils.populateModificationAwareColorScheme(mutableFillColorScheme, this.modifiedTimelines.get(comp).getTimelinePosition()); - RadianceColorScheme baseMarkScheme = RadianceColorSchemeUtilities.getColorScheme( - this.tabPane, tabIndex, - RadianceThemingSlices.ColorSchemeAssociationKind.FILL, + RadianceColorScheme baseMarkScheme = RadianceColorSchemeUtilities.getColorScheme( + this.tabPane, tabIndex, RadianceThemingSlices.ColorSchemeAssociationKind.FILL, this.getTabState(tabIndex, true)); - paintCloseButtonImage(graphics, - this.tabPane, orig.width, orig.height, toPaintCloseBorder, - mutableFillColorScheme, baseMarkScheme); + paintCloseButtonImage(graphics, this.tabPane, orig.width, orig.height, + toPaintCloseBorder, mutableFillColorScheme, baseMarkScheme); + } } else { - BladeUtils.populateColorScheme(mutableFillColorScheme, this.tabPane, tabIndex, + if (skin instanceof TonalSkin) { + BladeUtils.populateColorTokens(mutableColorTokens, this.tabPane, tabIndex, + modelStateInfo, this.getTabState(tabIndex, true), + RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB); + + paintCloseButtonImage(graphics, this.tabPane, orig.width, orig.height, + toPaintCloseBorder, mutableColorTokens); + } else { + BladeUtils.populateColorScheme(mutableFillColorScheme, this.tabPane, tabIndex, modelStateInfo, this.getTabState(tabIndex, true), - RadianceThemingSlices.ColorSchemeAssociationKind.TAB, - true); - BladeUtils.populateColorScheme(mutableMarkColorScheme, this.tabPane, tabIndex, + RadianceThemingSlices.ColorSchemeAssociationKind.TAB, true); + BladeUtils.populateColorScheme(mutableMarkColorScheme, this.tabPane, tabIndex, modelStateInfo, this.getTabState(tabIndex, true), - RadianceThemingSlices.ColorSchemeAssociationKind.FILL, - true); + RadianceThemingSlices.ColorSchemeAssociationKind.FILL, true); - paintCloseButtonImage(graphics, - this.tabPane, orig.width, orig.height, toPaintCloseBorder, - mutableFillColorScheme, mutableMarkColorScheme); + paintCloseButtonImage(graphics, this.tabPane, orig.width, orig.height, + toPaintCloseBorder, mutableFillColorScheme, mutableMarkColorScheme); + } } } } @@ -935,6 +1079,13 @@ public void drawColorSchemeIcon(Graphics2D g, RadianceColorScheme scheme, float direction, scheme, alpha); } + @Override + public void drawColorSchemeIcon(Graphics2D g, ContainerColorTokens colorTokens, float alpha) { + int fontSize = RadianceSizeUtils.getComponentFontSize(tabPane); + BladeArrowIconUtils.drawArrow(g, fontSize, getIconDimension(), + direction, colorTokens, alpha); + } + @Override public Dimension getIconDimension() { int fontSize = RadianceSizeUtils.getComponentFontSize(tabPane); @@ -1527,9 +1678,18 @@ protected Insets getContentBorderInsets(int tabPlacement) { @Override protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) { - RadianceColorScheme scheme = RadianceColorSchemeUtilities.getColorScheme(this.tabPane, - selectedIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB, ComponentState.ENABLED); - this.highlight = scheme.getSeparatorSecondaryColor(); + RadianceSkin skin = RadianceCoreUtilities.getSkin(this.tabPane); + if (skin instanceof TonalSkin) { + ContainerColorTokens colorTokens = RadianceColorSchemeUtilities.getContainerTokens( + this.tabPane, selectedIndex, RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, + ComponentState.ENABLED); + this.highlight = colorTokens.getInverseContainerOutline(); + } else { + RadianceColorScheme scheme = RadianceColorSchemeUtilities.getColorScheme( + this.tabPane, selectedIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB, + ComponentState.ENABLED); + this.highlight = scheme.getSeparatorSecondaryColor(); + } super.paintContentBorder(g, tabPlacement, selectedIndex); } @@ -1567,11 +1727,22 @@ protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int se // Draw unbroken line if tabs are not on BOTTOM, OR // selected tab is not in run adjacent to content, OR // selected tab is not visible (SCROLL_TAB_LAYOUT) - RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( - this.tabPane, selectedIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, + Color lineColor; + RadianceSkin skin = RadianceCoreUtilities.getSkin(this.tabPane); + if (skin instanceof TonalSkin) { + ContainerColorTokens colorTokens = RadianceColorSchemeUtilities.getContainerTokens( + this.tabPane, selectedIndex, + RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, ComponentState.SELECTED); - Color lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) + lineColor = colorTokens.getContainerOutline(); + } else { + RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( + this.tabPane, selectedIndex, + RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, + ComponentState.SELECTED); + lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) .getRepresentativeColor(borderScheme); + } graphics1X.setColor(lineColor); if (isUnbroken) { graphics1X.drawLine(0, scaledHeight - 1, scaledWidth - 1, scaledHeight - 1); @@ -1633,11 +1804,22 @@ protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int sele // Draw unbroken line if tabs are not on LEFT, OR // selected tab is not in run adjacent to content, OR // selected tab is not visible (SCROLL_TAB_LAYOUT) - RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( - this.tabPane, selectedIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, + Color lineColor; + RadianceSkin skin = RadianceCoreUtilities.getSkin(this.tabPane); + if (skin instanceof TonalSkin) { + ContainerColorTokens colorTokens = RadianceColorSchemeUtilities.getContainerTokens( + this.tabPane, selectedIndex, + RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, + ComponentState.SELECTED); + lineColor = colorTokens.getContainerOutline(); + } else { + RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( + this.tabPane, selectedIndex, + RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, ComponentState.SELECTED); - Color lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) + lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) .getRepresentativeColor(borderScheme); + } graphics1X.setColor(lineColor); if (isUnbroken) { graphics1X.drawLine(0, 0, 0, scaledHeight); @@ -1697,11 +1879,22 @@ protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int sel // Draw unbroken line if tabs are not on RIGHT, OR // selected tab is not in run adjacent to content, OR // selected tab is not visible (SCROLL_TAB_LAYOUT) - RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( - this.tabPane, selectedIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, + Color lineColor; + RadianceSkin skin = RadianceCoreUtilities.getSkin(this.tabPane); + if (skin instanceof TonalSkin) { + ContainerColorTokens colorTokens = RadianceColorSchemeUtilities.getContainerTokens( + this.tabPane, selectedIndex, + RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, + ComponentState.SELECTED); + lineColor = colorTokens.getContainerOutline(); + } else { + RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( + this.tabPane, selectedIndex, + RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, ComponentState.SELECTED); - Color lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) + lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) .getRepresentativeColor(borderScheme); + } graphics1X.setColor(lineColor); if (isUnbroken) { graphics1X.drawLine(scaledWidth - 1, 0, scaledWidth - 1, scaledHeight); @@ -1763,11 +1956,22 @@ protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selec // Draw unbroken line if tabs are not on TOP, OR // selected tab is not in run adjacent to content, OR // selected tab is not visible (SCROLL_TAB_LAYOUT) - RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( - this.tabPane, selectedIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, + Color lineColor; + RadianceSkin skin = RadianceCoreUtilities.getSkin(this.tabPane); + if (skin instanceof TonalSkin) { + ContainerColorTokens colorTokens = RadianceColorSchemeUtilities.getContainerTokens( + this.tabPane, selectedIndex, + RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, + ComponentState.SELECTED); + lineColor = colorTokens.getContainerOutline(); + } else { + RadianceColorScheme borderScheme = RadianceColorSchemeUtilities.getColorScheme( + this.tabPane, selectedIndex, + RadianceThemingSlices.ColorSchemeAssociationKind.TAB_BORDER, ComponentState.SELECTED); - Color lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) + lineColor = RadianceCoreUtilities.getBorderPainter(this.tabPane) .getRepresentativeColor(borderScheme); + } graphics1X.setColor(lineColor); if (isUnbroken) { graphics1X.drawLine(0, 0, scaledWidth, 0); @@ -1855,17 +2059,31 @@ protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics me : ComponentState.DISABLED_UNSELECTED; // System.out.println("Tab " + title + ":" + currState); - RadianceColorScheme scheme = RadianceColorSchemeUtilities.getColorScheme(tabPane, + Color fg; + RadianceSkin skin = RadianceCoreUtilities.getSkin(this.tabPane); + if (skin instanceof TonalSkin) { + ContainerColorTokens colorTokens = RadianceColorSchemeUtilities.getContainerTokens(tabPane, + tabIndex, RadianceThemingSlices.ContainerColorTokensAssociationKind.TAB, currState); + fg = colorTokens.getOnContainer(); + if (currState.isDisabled()) { + float fgAlpha = colorTokens.getOnContainerDisabledAlpha(); + if (fgAlpha < 1.0f) { + fg = RadianceColorUtilities.getAlphaColor(fg, (int) (255 * fgAlpha)); + } + } + } else { + RadianceColorScheme scheme = RadianceColorSchemeUtilities.getColorScheme(tabPane, tabIndex, RadianceThemingSlices.ColorSchemeAssociationKind.TAB, currState); - Color fg = scheme.getForegroundColor(); - - Graphics2D graphics = (Graphics2D) g.create(); - if (currState.isDisabled()) { - Color bgFillColor = RadianceColorUtilities.getBackgroundFillColor(this.tabPane); - fg = RadianceColorUtilities.getInterpolatedColor(fg, bgFillColor, + fg = scheme.getForegroundColor(); + if (currState.isDisabled()) { + Color bgFillColor = RadianceColorUtilities.getBackgroundFillColor(this.tabPane); + fg = RadianceColorUtilities.getInterpolatedColor(fg, bgFillColor, RadianceColorSchemeUtilities.getAlpha( - this.tabPane.getComponentAt(tabIndex), currState)); + this.tabPane.getComponentAt(tabIndex), currState)); + } } + + Graphics2D graphics = (Graphics2D) g.create(); graphics.clip(getTabRectangle(tabIndex)); RadianceTextUtilities.paintText(graphics, textRect, title, mnemIndex, graphics.getFont(), fg, null); @@ -1891,13 +2109,15 @@ protected void paintIcon(Graphics g, int tabPlacement, int tabIndex, Icon icon, // No support yet for transitions between disabled and enabled / active // states Icon disabledIcon = RadianceCoreUtilities.getFilteredIcon(this.tabPane, - icon, currentState, this.tabTextColorMap.get(tabIndex)); + icon, currentState, this.tabTextColorMap.get(tabIndex), + RadianceThemingSlices.ContainerType.NEUTRAL); disabledIcon.paintIcon(this.tabPane, g2d, 0, 0); } else { // Active states are painted on top of the icon that corresponds to the // enabled state Icon enabledIcon = RadianceCoreUtilities.getFilteredIcon(this.tabPane, - icon, ComponentState.ENABLED, this.tabTextColorMap.get(tabIndex)); + icon, ComponentState.ENABLED, this.tabTextColorMap.get(tabIndex), + RadianceThemingSlices.ContainerType.MUTED); enabledIcon.paintIcon(this.tabPane, g2d, 0, 0); if ((tabTracker != null) && (tabTracker.getActiveStrength() > 0.0f)) { for (Map.Entry entry : @@ -1908,7 +2128,8 @@ protected void paintIcon(Graphics g, int tabPlacement, int tabIndex, Icon icon, float contribution = entry.getValue().getContribution(); if (contribution > 0.0f) { Icon activeIcon = RadianceCoreUtilities.getFilteredIcon(this.tabPane, - icon, entry.getKey(), this.tabTextColorMap.get(tabIndex)); + icon, entry.getKey(), this.tabTextColorMap.get(tabIndex), + RadianceThemingSlices.ContainerType.MUTED); if (activeIcon != enabledIcon) { g2d.setComposite(WidgetUtilities.getAlphaComposite(this.tabPane, contribution, g)); diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceColorSchemeUtilities.java b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceColorSchemeUtilities.java index cae0fa68d..ff084fc22 100644 --- a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceColorSchemeUtilities.java +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceColorSchemeUtilities.java @@ -44,8 +44,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.List; import java.util.*; +import java.util.List; /** * Utilities related to color schemes. This class is for internal use only. @@ -126,24 +126,58 @@ private static RadianceColorScheme getColorizedScheme(Component component, * @return The color scheme of the specified tabbed pane tab. */ public static RadianceColorScheme getColorScheme(final JTabbedPane jtp, final int tabIndex, - RadianceThemingSlices.ColorSchemeAssociationKind associationKind, ComponentState componentState) { + RadianceThemingSlices.ColorSchemeAssociationKind associationKind, ComponentState componentState) { RadianceSkin skin = RadianceCoreUtilities.getSkin(jtp); if (skin == null) { RadianceCoreUtilities.traceRadianceApiUsage(jtp, - "Radiance delegate used when Radiance is not the current LAF"); + "Radiance delegate used when Radiance is not the current LAF"); } RadianceColorScheme nonColorized = skin.getColorScheme(jtp, associationKind, - componentState); + componentState); if (tabIndex >= 0) { Component component = jtp.getComponentAt(tabIndex); return getColorizedScheme(component, nonColorized, - jtp.getForegroundAt(tabIndex), jtp.getBackgroundAt(tabIndex), - !componentState.isDisabled()); + jtp.getForegroundAt(tabIndex), jtp.getBackgroundAt(tabIndex), + !componentState.isDisabled()); } else { return getColorizedScheme(jtp, nonColorized, !componentState.isDisabled()); } } + /** + * Returns the color scheme of the specified tabbed pane tab. + * + * @param jtp Tabbed pane. + * @param tabIndex Tab index. + * @param componentState Tab component state. + * @return The color scheme of the specified tabbed pane tab. + */ + public static ContainerColorTokens getContainerTokens(final JTabbedPane jtp, final int tabIndex, + RadianceThemingSlices.ContainerColorTokensAssociationKind associationKind, + ComponentState componentState) { + RadianceSkin skin = RadianceCoreUtilities.getSkin(jtp); + if (skin == null) { + RadianceCoreUtilities.traceRadianceApiUsage(jtp, + "Radiance delegate used when Radiance is not the current LAF"); + } + // TODO: TONAL - container type + ContainerColorTokens nonColorized = skin.getContainerTokens(jtp, associationKind, + componentState, + (tabIndex == jtp.getSelectedIndex()) + ? RadianceThemingSlices.ContainerType.TONAL + : RadianceThemingSlices.ContainerType.MUTED); + return nonColorized; + // TODO: TONAL - colorization +// if (tabIndex >= 0) { +// Component component = jtp.getComponentAt(tabIndex); +// return getColorizedScheme(component, nonColorized, +// jtp.getForegroundAt(tabIndex), jtp.getBackgroundAt(tabIndex), +// !componentState.isDisabled()); +// } else { +// return getColorizedScheme(jtp, nonColorized, !componentState.isDisabled()); +// } + } + /** * Returns the color scheme of the specified component. * diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceCoreUtilities.java b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceCoreUtilities.java index 2c68676b3..bf7463285 100644 --- a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceCoreUtilities.java +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/utils/RadianceCoreUtilities.java @@ -67,8 +67,8 @@ import java.awt.event.AWTEventListener; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; -import java.util.List; import java.util.*; +import java.util.List; /** * Various utility functions. This class is for internal use only. @@ -944,24 +944,43 @@ public static Icon getFilteredIcon(JComponent comp, Icon orig, ComponentState co } public static Icon getFilteredIcon(JTabbedPane tab, Icon orig, - ComponentState componentState, Color textColor) { + ComponentState componentState, Color textColor, + RadianceThemingSlices.ContainerType inactiveContainerType) { double scale = RadianceCommonCortex.getScaleFactor(tab); RadianceThemingSlices.IconFilterStrategy iconFilterStrategy = getIconFilterStrategy(tab, componentState); RadianceColorScheme colorScheme = RadianceColorSchemeUtilities.getColorScheme( tab, componentState); - switch (iconFilterStrategy) { - case ORIGINAL: - return orig; - case THEMED_FOLLOW_TEXT: - Color foreground = (textColor != null) ? textColor - : colorScheme.getForegroundColor(); - return new ScaleAwareImageWrapperIcon(RadianceImageCreator.getColorImage( + RadianceSkin skin = RadianceCoreUtilities.getSkin(tab); + if (skin instanceof TonalSkin) { + ContainerColorTokens colorTokens = + RadianceColorSchemeUtilities.getContainerTokens(tab, componentState, inactiveContainerType); + switch (iconFilterStrategy) { + case ORIGINAL: + return orig; + case THEMED_FOLLOW_TEXT: + Color foreground = (textColor != null) ? textColor : colorTokens.getOnContainer(); + return new ScaleAwareImageWrapperIcon(RadianceImageCreator.getColorImage( tab, orig, foreground, 1.0f), scale); - case THEMED_FOLLOW_COLOR_SCHEME: - float brightnessFactor = colorScheme.isDark() ? 0.2f : 0.8f; - return new ScaleAwareImageWrapperIcon(RadianceImageCreator.getColorSchemeImage( + case THEMED_FOLLOW_COLOR_SCHEME: + // TODO: TONAL - check brightness + //float brightnessFactor = colorScheme.isDark() ? 0.2f : 0.8f; + return new ScaleAwareImageWrapperIcon(RadianceImageCreator.getContainerTokensImage( + tab, orig, colorTokens, 0.4f), scale); + } + } else { + switch (iconFilterStrategy) { + case ORIGINAL: + return orig; + case THEMED_FOLLOW_TEXT: + Color foreground = (textColor != null) ? textColor : colorScheme.getForegroundColor(); + return new ScaleAwareImageWrapperIcon(RadianceImageCreator.getColorImage( + tab, orig, foreground, 1.0f), scale); + case THEMED_FOLLOW_COLOR_SCHEME: + float brightnessFactor = colorScheme.isDark() ? 0.2f : 0.8f; + return new ScaleAwareImageWrapperIcon(RadianceImageCreator.getColorSchemeImage( tab, orig, colorScheme, brightnessFactor), scale); + } } return null; }