diff --git a/demos/theming-demo/src/main/java/org/pushingpixels/radiance/demo/theming/main/palette/TonalCheck.java b/demos/theming-demo/src/main/java/org/pushingpixels/radiance/demo/theming/main/palette/TonalCheck.java index f6a5c06ac..f12615424 100644 --- a/demos/theming-demo/src/main/java/org/pushingpixels/radiance/demo/theming/main/palette/TonalCheck.java +++ b/demos/theming-demo/src/main/java/org/pushingpixels/radiance/demo/theming/main/palette/TonalCheck.java @@ -32,7 +32,7 @@ import org.pushingpixels.radiance.demo.theming.main.Check; import org.pushingpixels.radiance.theming.api.RadianceSkin; import org.pushingpixels.radiance.theming.api.RadianceThemingCortex; -import org.pushingpixels.radiance.theming.api.skin.GeminiSkin; +import org.pushingpixels.radiance.theming.api.skin.NebulaSkin; import javax.swing.*; import java.awt.*; @@ -41,7 +41,7 @@ public class TonalCheck { public static void main(String[] args) { - RadianceSkin tonalSkin = new GeminiSkin.GeminiTonalSkin(); + RadianceSkin tonalSkin = new NebulaSkin.NebulaTonalSkin(); RadianceThemingCortex.GlobalScope.registerWidget("org.pushingpixels.radiance.theming" + ".extras.api.tabbed.TabHoverPreviewWidget", JTabbedPane.class, false); diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/NebulaAccentedTonalSkin.java b/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/NebulaAccentedTonalSkin.java new file mode 100644 index 000000000..a18abf2c8 --- /dev/null +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/NebulaAccentedTonalSkin.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2005-2025 Radiance Kirill Grouchnikov. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.pushingpixels.radiance.theming.api.skin; + +import org.pushingpixels.ephemeral.chroma.hct.Hct; +import org.pushingpixels.radiance.theming.api.*; +import org.pushingpixels.radiance.theming.api.colorscheme.ContainerColorTokensSingleColorQuery; +import org.pushingpixels.radiance.theming.api.colorscheme.RadianceColorScheme; +import org.pushingpixels.radiance.theming.api.painter.border.FlatTonalBorderPainter; +import org.pushingpixels.radiance.theming.api.painter.decoration.ArcDecorationPainter; +import org.pushingpixels.radiance.theming.api.painter.decoration.MarbleNoiseDecorationPainter; +import org.pushingpixels.radiance.theming.api.painter.fill.ClassicTonalFillPainter; +import org.pushingpixels.radiance.theming.api.painter.fill.SpecularRectangularFillPainter; +import org.pushingpixels.radiance.theming.api.painter.overlay.BottomLineTonalOverlayPainter; +import org.pushingpixels.radiance.theming.api.painter.overlay.RadianceOverlayPainter; +import org.pushingpixels.radiance.theming.api.painter.overlay.TopShadowOverlayPainter; +import org.pushingpixels.radiance.theming.api.palette.ColorSchemeUtils; +import org.pushingpixels.radiance.theming.api.palette.ContainerColorTokens; +import org.pushingpixels.radiance.theming.api.palette.ExtendedContainerColorTokens; +import org.pushingpixels.radiance.theming.api.palette.RadianceColorScheme2; +import org.pushingpixels.radiance.theming.api.shaper.ClassicButtonShaper; + +/** + * Base class for accented Nebula skins. This class is part of officially supported API. + * + * @author Kirill Grouchnikov + */ +public abstract class NebulaAccentedTonalSkin extends RadianceSkin.TonalAccented { + /** + * Overlay painter to paint separator lines on some decoration areas. + */ + protected RadianceOverlayPainter bottomLineOverlayPainter; + + /** + * Creates a new accented Nebula skin. + */ + protected NebulaAccentedTonalSkin(AccentBuilder accentBuilder) { + super(accentBuilder); + + RadianceColorScheme2 nebulaColorScheme = ColorSchemeUtils.getColorScheme( + /* palettesSource */ new ColorSchemeUtils.FidelityPaletteSource( + Hct.fromInt(0xFFBAD2E3), Hct.fromInt(0xFFD7DBE1), Hct.fromInt(0xFFF3F7FD)), + /* activeStatesContainerType */ RadianceThemingSlices.ActiveContainerType.TONAL, + /* isDark */ false); + + ContainerColorTokens nebulaRolloverContainerTokens = ColorSchemeUtils.getContainerTokens( + /* seed */ Hct.fromInt(0xFF6B92AF), + /* activeStatesContainerType */ RadianceThemingSlices.ActiveContainerType.TONAL, + /* isFidelity */ true, + /* isDark */ true); + ContainerColorTokens nebulaPressedContainerTokens = ColorSchemeUtils.getContainerTokens( + /* seed */ Hct.fromInt(0xFF276792), + /* activeStatesContainerType */ RadianceThemingSlices.ActiveContainerType.TONAL, + /* isFidelity */ true, + /* isDark */ true); + ContainerColorTokens nebulaSelectedHighlightContainerTokens = + ColorSchemeUtils.getContainerTokens( + /* seed */ Hct.fromInt(0xFF5B85A6), + /* activeStatesContainerType */ RadianceThemingSlices.ActiveContainerType.TONAL, + /* isFidelity */ true, + /* isDark */ true); + ContainerColorTokens nebulaDeterminateContainerTokens = ColorSchemeUtils.getContainerTokens( + /* seed */ Hct.fromInt(0xFFD2852F), + /* activeStatesContainerType */ RadianceThemingSlices.ActiveContainerType.TONAL, + /* isFidelity */ true, + /* isDark */ true); + + RadianceColorSchemeBundle2 nebulaDefaultBundle = + new RadianceColorSchemeBundle2(nebulaColorScheme); + nebulaDefaultBundle.registerActiveContainerTokens(nebulaPressedContainerTokens, + ComponentState.PRESSED_SELECTED, ComponentState.PRESSED_UNSELECTED, + ComponentState.ARMED, ComponentState.ROLLOVER_ARMED); + + // Highlights + nebulaDefaultBundle.registerActiveContainerTokens(nebulaRolloverContainerTokens, + RadianceThemingSlices.ContainerColorTokensAssociationKind.HIGHLIGHT, + ComponentState.ROLLOVER_SELECTED, ComponentState.ROLLOVER_UNSELECTED); + nebulaDefaultBundle.registerActiveContainerTokens(nebulaSelectedHighlightContainerTokens, + RadianceThemingSlices.ContainerColorTokensAssociationKind.HIGHLIGHT, + ComponentState.SELECTED); + + // Progress bars + nebulaDefaultBundle.registerActiveContainerTokens(nebulaDeterminateContainerTokens, + ComponentState.DETERMINATE, ComponentState.INDETERMINATE); + + this.registerDecorationAreaSchemeBundle(nebulaDefaultBundle, + RadianceThemingSlices.DecorationAreaType.NONE); + + ExtendedContainerColorTokens nebulaDecorationsColorTokens = ColorSchemeUtils.getExtendedContainerTokens( + /* seed */ Hct.fromInt(0xFFC2D1DA), + /* isFidelity */ true, + /* isDark */ false); + this.registerAsDecorationArea(nebulaDecorationsColorTokens, + RadianceThemingSlices.DecorationAreaType.CONTROL_PANE, + RadianceThemingSlices.DecorationAreaType.FOOTER); + + RadianceColorSchemeBundle2 nebulaDefaultHeaderBundle = + new RadianceColorSchemeBundle2(this.getWindowChromeAccent()); + if (this.getWindowChromeHighlightsAccent() != null) { + nebulaDefaultHeaderBundle.registerActiveContainerTokens( + this.getWindowChromeHighlightsAccent(), + RadianceThemingSlices.ContainerColorTokensAssociationKind.HIGHLIGHT, + ComponentState.getActiveStates()); + } + this.registerDecorationAreaSchemeBundle(nebulaDefaultHeaderBundle, + nebulaDefaultHeaderBundle.getMainColorScheme().getExtendedNeutralContainerTokens(), + RadianceThemingSlices.DecorationAreaType.PRIMARY_TITLE_PANE, + RadianceThemingSlices.DecorationAreaType.SECONDARY_TITLE_PANE, + RadianceThemingSlices.DecorationAreaType.HEADER); + + // add an overlay painter to paint a drop shadow along the top edge of toolbars + this.addOverlayPainter(TopShadowOverlayPainter.getInstance(60), + RadianceThemingSlices.DecorationAreaType.TOOLBAR); + + // add an overlay painter to paint separator lines along the bottom + // edges of title panes and menu bars + this.bottomLineOverlayPainter = new BottomLineTonalOverlayPainter( + ContainerColorTokensSingleColorQuery.CONTAINER_OUTLINE); + this.addOverlayPainter(bottomLineOverlayPainter, + RadianceThemingSlices.DecorationAreaType.PRIMARY_TITLE_PANE, + RadianceThemingSlices.DecorationAreaType.SECONDARY_TITLE_PANE, + RadianceThemingSlices.DecorationAreaType.HEADER); + + this.buttonShaper = new ClassicButtonShaper(); + this.fillPainter = new SpecularRectangularFillPainter(new ClassicTonalFillPainter(), 1.0f); + this.borderPainter = new FlatTonalBorderPainter(); + + MarbleNoiseDecorationPainter decorationPainter = new MarbleNoiseDecorationPainter(); + decorationPainter.setBaseDecorationPainter(new ArcDecorationPainter()); + decorationPainter.setTextureAlpha(0.5f); + this.decorationPainter = decorationPainter; + + this.highlightFillPainter = new ClassicTonalFillPainter(); + + // TODO - TONAL : remove this altogether + ColorSchemes schemes = RadianceSkin.getColorSchemes( + this.getClass().getClassLoader().getResourceAsStream( + "org/pushingpixels/radiance/theming/api/skin/nebula.colorschemes")); + + RadianceColorScheme activeScheme = schemes.get("Nebula Active"); + RadianceColorScheme enabledScheme = schemes.get("Nebula Enabled"); + RadianceColorScheme rolloverUnselectedScheme = schemes.get("Nebula Rollover Unselected"); + RadianceColorScheme pressedScheme = schemes.get("Nebula Pressed"); + RadianceColorScheme rolloverSelectedScheme = schemes.get("Nebula Rollover Selected"); + RadianceColorScheme disabledScheme = schemes.get("Nebula Disabled"); + + RadianceColorSchemeBundle defaultSchemeBundle = new RadianceColorSchemeBundle( + activeScheme, enabledScheme, disabledScheme); + defaultSchemeBundle.registerColorScheme(rolloverUnselectedScheme, + ComponentState.ROLLOVER_UNSELECTED); + defaultSchemeBundle.registerColorScheme(rolloverSelectedScheme, + ComponentState.ROLLOVER_SELECTED); + defaultSchemeBundle.registerColorScheme(pressedScheme, + ComponentState.PRESSED_SELECTED, ComponentState.PRESSED_UNSELECTED, + ComponentState.ARMED, ComponentState.ROLLOVER_ARMED); + + defaultSchemeBundle.registerColorScheme(rolloverUnselectedScheme, + RadianceThemingSlices.ColorSchemeAssociationKind.BORDER, ComponentState.SELECTED); + + defaultSchemeBundle.registerHighlightAlpha(0.6f, ComponentState.ROLLOVER_UNSELECTED); + defaultSchemeBundle.registerHighlightAlpha(0.8f, ComponentState.SELECTED, ComponentState.ARMED, + ComponentState.ROLLOVER_ARMED); + defaultSchemeBundle.registerHighlightAlpha(0.95f, ComponentState.ROLLOVER_SELECTED); + defaultSchemeBundle.registerHighlightColorScheme(pressedScheme, ComponentState.ROLLOVER_UNSELECTED, + ComponentState.SELECTED, ComponentState.ROLLOVER_SELECTED, + ComponentState.ARMED, ComponentState.ROLLOVER_ARMED); + + // for progress bars + RadianceColorScheme determinateScheme = schemes.get("Nebula Determinate"); + RadianceColorScheme determinateBorderScheme = schemes.get("Nebula Determinate Border"); + defaultSchemeBundle.registerColorScheme(determinateScheme, + ComponentState.DETERMINATE, ComponentState.INDETERMINATE); + defaultSchemeBundle.registerColorScheme(determinateBorderScheme, + RadianceThemingSlices.ColorSchemeAssociationKind.BORDER, + ComponentState.DETERMINATE, ComponentState.INDETERMINATE); + + RadianceColorScheme determinateDisabledScheme = schemes + .get("Nebula Determinate Disabled"); + RadianceColorScheme determinateDisabledBorderScheme = schemes + .get("Nebula Determinate Disabled Border"); + defaultSchemeBundle.registerColorScheme(determinateDisabledScheme, + ComponentState.DISABLED_DETERMINATE, ComponentState.DISABLED_INDETERMINATE); + defaultSchemeBundle.registerColorScheme( + determinateDisabledBorderScheme, + RadianceThemingSlices.ColorSchemeAssociationKind.BORDER, + ComponentState.DISABLED_DETERMINATE, ComponentState.DISABLED_INDETERMINATE); + + this.registerDecorationAreaSchemeBundle(defaultSchemeBundle, + RadianceThemingSlices.DecorationAreaType.NONE); + + this.registerDecorationAreaSchemeBundle(defaultSchemeBundle, RadianceThemingSlices.DecorationAreaType.NONE); + + this.registerAsDecorationArea(schemes.get("Nebula Decorations"), + bundle -> bundle.registerColorScheme(schemes.get("Nebula Decorations Separator"), + RadianceThemingSlices.ColorSchemeAssociationKind.SEPARATOR), + RadianceThemingSlices.DecorationAreaType.FOOTER, RadianceThemingSlices.DecorationAreaType.CONTROL_PANE); + } +} diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/NebulaSkin.java b/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/NebulaSkin.java index 801ffce3c..d8f31fd97 100644 --- a/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/NebulaSkin.java +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/NebulaSkin.java @@ -29,6 +29,10 @@ */ package org.pushingpixels.radiance.theming.api.skin; +import org.pushingpixels.ephemeral.chroma.hct.Hct; +import org.pushingpixels.radiance.theming.api.RadianceThemingSlices; +import org.pushingpixels.radiance.theming.api.palette.ColorSchemeUtils; + /** * Nebula skin. This class is part of officially supported API. * @@ -53,4 +57,27 @@ public NebulaSkin() { public String getDisplayName() { return NAME; } + + public static class NebulaTonalSkin extends NebulaAccentedTonalSkin { + public static final String NAME = "Nebula Tonal"; + + public NebulaTonalSkin() { + super(new AccentBuilder() + .withWindowChromeAccent(ColorSchemeUtils.getColorScheme( + /* palettesSource */ new ColorSchemeUtils.FidelityPaletteSource( + Hct.fromInt(0xFFBAD2E3), Hct.fromInt(0xFFD7DBE1), Hct.fromInt(0xFFD6E3EE)), + /* activeStatesContainerType */ RadianceThemingSlices.ActiveContainerType.TONAL, + /* isDark */ false)) + .withWindowChromeHighlightsAccent(ColorSchemeUtils.getContainerTokens( + /* seed */ Hct.fromInt(0xFF6B92AF), + /* activeStatesContainerType */ RadianceThemingSlices.ActiveContainerType.TONAL, + /* isFidelity */ true, + /* isDark */ true))); + } + + @Override + public String getDisplayName() { + return NAME; + } + } } diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/RadianceNebulaLookAndFeel.java b/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/RadianceNebulaLookAndFeel.java index b58946771..5fbe8fc3b 100644 --- a/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/RadianceNebulaLookAndFeel.java +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/api/skin/RadianceNebulaLookAndFeel.java @@ -51,4 +51,10 @@ public class RadianceNebulaLookAndFeel extends RadianceLookAndFeel { public RadianceNebulaLookAndFeel() { super(new NebulaSkin()); } + + public static class RadianceNebulaTonalLookAndFeel extends RadianceLookAndFeel { + public RadianceNebulaTonalLookAndFeel() { + super(new NebulaSkin.NebulaTonalSkin()); + } + } } diff --git a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/plugin/BaseSkinPlugin.java b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/plugin/BaseSkinPlugin.java index a366ee42a..c5f03550f 100644 --- a/theming/src/main/java/org/pushingpixels/radiance/theming/internal/plugin/BaseSkinPlugin.java +++ b/theming/src/main/java/org/pushingpixels/radiance/theming/internal/plugin/BaseSkinPlugin.java @@ -141,6 +141,9 @@ public Set getSkins() { result.add(new SkinInfo(GeminiSkin.GeminiTonalSkin.NAME, GeminiSkin.GeminiTonalSkin.class::getName, RadianceGeminiLookAndFeel.RadianceGeminiTonalLookAndFeel.class::getName)); + result.add(new SkinInfo(NebulaSkin.NebulaTonalSkin.NAME, + NebulaSkin.NebulaTonalSkin.class::getName, + RadianceNebulaLookAndFeel.RadianceNebulaTonalLookAndFeel.class::getName)); return result; }