Skip to content

Commit

Permalink
First pass for top-level window decorations in the tonal world
Browse files Browse the repository at this point in the history
Title pane + root pane border for #400
  • Loading branch information
kirill-grouchnikov committed Dec 1, 2024
1 parent 3a98328 commit d323af3
Show file tree
Hide file tree
Showing 9 changed files with 645 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ public SampleSkin(RadianceColorScheme accentScheme) {
this.registerDecorationAreaColorScheme(lightColorScheme,
RadianceThemingSlices.DecorationAreaType.NONE);

this.registerAsDecorationArea(lightColorScheme.getTonalContainerTokens(),
RadianceThemingSlices.DecorationAreaType.PRIMARY_TITLE_PANE,
RadianceThemingSlices.DecorationAreaType.SECONDARY_TITLE_PANE,
RadianceThemingSlices.DecorationAreaType.HEADER);

this.buttonShaper = new ClassicButtonShaper();
this.fillPainter = new ClassicTonalFillPainter();
this.borderPainter = new ClassicTonalBorderPainter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ public RadianceColorScheme getWindowChromeAccent() {
*/
private Map<RadianceThemingSlices.DecorationAreaType, RadianceColorScheme> backgroundColorSchemeMap;

private Map<RadianceThemingSlices.DecorationAreaType, ContainerRenderColorTokens> tonalBackgroundRenderColorTokensMap;

/**
* Maps decoration area type to the registered overlay painters. Each
* decoration area type can have more than one overlay painter.
Expand Down Expand Up @@ -263,6 +265,7 @@ protected RadianceSkin() {
this.colorSchemeBundleMap = new HashMap<>();
this.tonalColorSchemeMap = new HashMap<>();
this.backgroundColorSchemeMap = new HashMap<>();
this.tonalBackgroundRenderColorTokensMap = new HashMap<>();
this.overlayPaintersMap = new HashMap<>();
this.colorOverlayMap = new HashMap<>();

Expand Down Expand Up @@ -552,23 +555,23 @@ public void registerDecorationAreaSchemeBundle(
this.statesWithAlpha.addAll(bundle.getStatesWithAlpha());
}

/**
* Registers the specified color scheme bundle and background color scheme
* to be used on controls in decoration areas.
*
* @param bundle The color scheme bundle to use on controls in decoration
* areas.
* @param areaTypes Enumerates the area types that are affected by the parameters.
*/
public void registerDecorationAreaColorScheme(RadianceColorScheme2 colorScheme,
public void registerDecorationAreaColorScheme(
RadianceColorScheme2 colorScheme,
ContainerRenderColorTokens backgroundRenderColorTokens,
RadianceThemingSlices.DecorationAreaType... areaTypes) {
if (colorScheme == null) {
return;
}

if (backgroundRenderColorTokens == null) {
throw new IllegalArgumentException(
"Cannot pass null background color render tokens");
}

for (RadianceThemingSlices.DecorationAreaType areaType : areaTypes) {
this.decoratedAreaSet.add(areaType);
this.tonalColorSchemeMap.put(areaType, colorScheme);
this.tonalBackgroundRenderColorTokensMap.put(areaType, backgroundRenderColorTokens);
}
}

Expand All @@ -586,6 +589,12 @@ public void registerDecorationAreaSchemeBundle(
areaTypes);
}

public void registerDecorationAreaColorScheme(
RadianceColorScheme2 colorScheme, RadianceThemingSlices.DecorationAreaType... areaTypes) {
this.registerDecorationAreaColorScheme(colorScheme, colorScheme.getMutedContainerTokens(),
areaTypes);
}

/**
* Registers the specified background color scheme to be used on controls in
* decoration areas.
Expand All @@ -608,6 +617,18 @@ public void registerAsDecorationArea(RadianceColorScheme backgroundColorScheme,
}
}

public void registerAsDecorationArea(ContainerRenderColorTokens backgroundRenderColorTokens,
RadianceThemingSlices.DecorationAreaType... areaTypes) {
if (backgroundRenderColorTokens == null) {
throw new IllegalArgumentException(
"Cannot pass null background color tokens");
}
for (RadianceThemingSlices.DecorationAreaType areaType : areaTypes) {
this.decoratedAreaSet.add(areaType);
this.tonalBackgroundRenderColorTokensMap.put(areaType, backgroundRenderColorTokens);
}
}

/**
* Registers the specified background color scheme and a color scheme bundle overlay to be used
* on controls in decoration areas.
Expand Down Expand Up @@ -937,6 +958,24 @@ public final RadianceColorScheme getBackgroundColorScheme(RadianceThemingSlices.
return this.backgroundColorSchemeMap.get(RadianceThemingSlices.DecorationAreaType.NONE);
}

public final ContainerRenderColorTokens getBackgroundRenderColorTokens(
RadianceThemingSlices.DecorationAreaType decorationAreaType) {
// 1 - check the registered background scheme for this specific area type.
if (this.tonalBackgroundRenderColorTokensMap.containsKey(decorationAreaType)) {
return this.tonalBackgroundRenderColorTokensMap.get(decorationAreaType);
}
// 2 - check the registered scheme bundle for this specific area type.
if (this.tonalColorSchemeMap.containsKey(decorationAreaType)) {
ContainerRenderColorTokens registered = this.tonalColorSchemeMap.get(
decorationAreaType).getMutedContainerTokens();
if (registered != null) {
return registered;
}
}
// 3 - return the background scheme for the default area type
return this.tonalBackgroundRenderColorTokensMap.get(RadianceThemingSlices.DecorationAreaType.NONE);
}

public void setOverlayColor(Color color, RadianceThemingSlices.ColorOverlayType colorOverlayType,
RadianceThemingSlices.DecorationAreaType decorationAreaType, ComponentState... componentStates) {
if (!this.colorOverlayMap.containsKey(colorOverlayType)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@
*/
package org.pushingpixels.radiance.theming.api.painter.decoration;

import org.pushingpixels.radiance.theming.api.RadianceThemingSlices;
import org.pushingpixels.radiance.theming.api.RadianceSkin;
import org.pushingpixels.radiance.theming.api.RadianceThemingSlices;
import org.pushingpixels.radiance.theming.api.colorscheme.RadianceColorScheme;
import org.pushingpixels.radiance.theming.api.palette.ContainerRenderColorTokens;
import org.pushingpixels.radiance.theming.api.palette.TonalSkin;
import org.pushingpixels.radiance.theming.internal.utils.RadianceCoreUtilities;

import javax.swing.*;
Expand All @@ -58,14 +60,26 @@ public String getDisplayName() {

@Override
public void paintDecorationArea(Graphics2D graphics, Component comp,
RadianceThemingSlices.DecorationAreaType decorationAreaType, int width, int height, RadianceSkin skin) {
if ((decorationAreaType == RadianceThemingSlices.DecorationAreaType.PRIMARY_TITLE_PANE)
|| (decorationAreaType == RadianceThemingSlices.DecorationAreaType.SECONDARY_TITLE_PANE)) {
this.paintTitleBackground(graphics, comp, width, height,
skin.getBackgroundColorScheme(decorationAreaType));
RadianceThemingSlices.DecorationAreaType decorationAreaType, int width, int height,
RadianceSkin skin) {
if (skin instanceof TonalSkin) {
if ((decorationAreaType == RadianceThemingSlices.DecorationAreaType.PRIMARY_TITLE_PANE) ||
(decorationAreaType == RadianceThemingSlices.DecorationAreaType.SECONDARY_TITLE_PANE)) {
this.paintTitleBackground(graphics, comp, width, height,
skin.getBackgroundRenderColorTokens(decorationAreaType));
} else {
this.paintExtraBackground(graphics, RadianceCoreUtilities.getHeaderParent(comp),
comp, width, height, skin.getBackgroundRenderColorTokens(decorationAreaType));
}
} else {
this.paintExtraBackground(graphics, RadianceCoreUtilities.getHeaderParent(comp), comp,
width, height, skin.getBackgroundColorScheme(decorationAreaType));
if ((decorationAreaType == RadianceThemingSlices.DecorationAreaType.PRIMARY_TITLE_PANE) ||
(decorationAreaType == RadianceThemingSlices.DecorationAreaType.SECONDARY_TITLE_PANE)) {
this.paintTitleBackground(graphics, comp, width, height,
skin.getBackgroundColorScheme(decorationAreaType));
} else {
this.paintExtraBackground(graphics, RadianceCoreUtilities.getHeaderParent(comp),
comp, width, height, skin.getBackgroundColorScheme(decorationAreaType));
}
}
}

Expand Down Expand Up @@ -100,7 +114,7 @@ private void paintTitleBackground(Graphics2D original, Component comp, int width
g2d.setClip(clipTop);
LinearGradientPaint gradientTop = new LinearGradientPaint(0, 0, width, 0,
new float[] { 0.0f, 0.5f, 1.0f }, new Color[] { scheme.getLightColor(),
scheme.getUltraLightColor(), scheme.getLightColor() },
scheme.getUltraLightColor(), scheme.getLightColor() },
CycleMethod.REPEAT);
g2d.setPaint(gradientTop);
g2d.fillRect(0, 0, width, height);
Expand Down Expand Up @@ -131,6 +145,59 @@ private void paintTitleBackground(Graphics2D original, Component comp, int width
g2d.dispose();
}

private void paintTitleBackground(Graphics2D original, Component comp, int width, int height,
ContainerRenderColorTokens renderColorTokens) {
// Create a new Graphics2D object so that we can apply clipping to it without having
// to reset the state after we're done
Graphics2D g2d = (Graphics2D) original.create();

// Fill background
GeneralPath clipTop = new GeneralPath();
clipTop.moveTo(0, 0);
clipTop.lineTo(width, 0);
clipTop.lineTo(width, height / 2);
clipTop.quadTo(width / 2, height / 4, 0, height / 2);
clipTop.lineTo(0, 0);

g2d.setClip(clipTop);
LinearGradientPaint gradientTop = new LinearGradientPaint(0, 0, width, 0,
new float[] { 0.0f, 0.5f, 1.0f }, new Color[] {
renderColorTokens.getContainerColorTokens().getContainer(),
renderColorTokens.getContainerColorTokens().getContainerLowest(),
renderColorTokens.getContainerColorTokens().getContainer() },
CycleMethod.REPEAT);
g2d.setPaint(gradientTop);
g2d.fillRect(0, 0, width, height);

GeneralPath clipBottom = new GeneralPath();
clipBottom.moveTo(0, height);
clipBottom.lineTo(width, height);
clipBottom.lineTo(width, height / 2);
clipBottom.quadTo(width / 2, height / 4, 0, height / 2);
clipBottom.lineTo(0, height);

g2d.setClip(clipBottom);
LinearGradientPaint gradientBottom = new LinearGradientPaint(0, 0, width, 0,
new float[] { 0.0f, 0.5f, 1.0f },
new Color[] {
renderColorTokens.getContainerColorTokens().getContainerHighest(),
renderColorTokens.getContainerColorTokens().getContainer(),
renderColorTokens.getContainerColorTokens().getContainerHighest() },
CycleMethod.REPEAT);
g2d.setPaint(gradientBottom);
g2d.fillRect(0, 0, width, height);

GeneralPath mid = new GeneralPath();
mid.moveTo(width, height / 2);
mid.quadTo(width / 2, height / 4, 0, height / 2);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setClip(new Rectangle(0, 0, width, height));
g2d.draw(mid);

g2d.dispose();
}

/**
* Paints the background of non-title decoration areas.
*
Expand Down Expand Up @@ -162,7 +229,34 @@ private void paintExtraBackground(Graphics2D graphics, Container parent, Compone
LinearGradientPaint gradientBottom = new LinearGradientPaint(-offset.x, 0,
-offset.x + pWidth, 0, new float[] { 0.0f, 0.5f, 1.0f },
new Color[] { scheme.getMidColor(), scheme.getLightColor(),
scheme.getMidColor() },
scheme.getMidColor() },
CycleMethod.REPEAT);
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.setPaint(gradientBottom);
g2d.fillRect(-offset.x, 0, pWidth, height);
g2d.dispose();
}
}

private void paintExtraBackground(Graphics2D graphics, Container parent, Component comp,
int width, int height, ContainerRenderColorTokens renderColorTokens) {
Point offset = RadianceCoreUtilities.getOffsetInRootPaneCoords(comp);
JRootPane rootPane = SwingUtilities.getRootPane(parent);
// fix for bug 234 - Window doesn't have a root pane.
JLayeredPane layeredPane = rootPane.getLayeredPane();
Insets layeredPaneInsets = (layeredPane != null) ? layeredPane.getInsets() : null;

int pWidth = (layeredPane == null) ? parent.getWidth()
: layeredPane.getWidth() - layeredPaneInsets.left - layeredPaneInsets.right;

if (pWidth != 0) {
LinearGradientPaint gradientBottom = new LinearGradientPaint(-offset.x, 0,
-offset.x + pWidth, 0, new float[] { 0.0f, 0.5f, 1.0f },
new Color[] {
renderColorTokens.getContainerColorTokens().getContainerHighest(),
renderColorTokens.getContainerColorTokens().getContainer(),
renderColorTokens.getContainerColorTokens().getContainerHighest()
},
CycleMethod.REPEAT);
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.setPaint(gradientBottom);
Expand Down Expand Up @@ -196,4 +290,34 @@ public void paintDecorationArea(Graphics2D graphics, Component comp, RadianceThe
g2d.dispose();
}
}

@Override
public void paintDecorationArea(Graphics2D graphics, Component comp,
RadianceThemingSlices.DecorationAreaType decorationAreaType, Shape contour,
ContainerRenderColorTokens renderColorTokens) {
Component parent = RadianceCoreUtilities.getHeaderParent(comp);
Point offset = RadianceCoreUtilities.getOffsetInRootPaneCoords(comp);
JRootPane rootPane = SwingUtilities.getRootPane(parent);
// fix for bug 234 - Window doesn't have a root pane.
JLayeredPane layeredPane = rootPane.getLayeredPane();
Insets layeredPaneInsets = (layeredPane != null) ? layeredPane.getInsets() : null;

int pWidth = (layeredPane == null) ? parent.getWidth()
: layeredPane.getWidth() - layeredPaneInsets.left - layeredPaneInsets.right;

if (pWidth != 0) {
LinearGradientPaint gradientBottom = new LinearGradientPaint(-offset.x, 0,
-offset.x + pWidth, 0, new float[] { 0.0f, 0.5f, 1.0f },
new Color[] {
renderColorTokens.getContainerColorTokens().getContainerHighest(),
renderColorTokens.getContainerColorTokens().getContainer(),
renderColorTokens.getContainerColorTokens().getContainerHighest()
},
CycleMethod.REPEAT);
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.setPaint(gradientBottom);
g2d.fill(contour);
g2d.dispose();
}
}
}
Loading

0 comments on commit d323af3

Please sign in to comment.