diff --git a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/DimmingFrameColorProvider.java b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/DimmingFrameColorProvider.java index 9c51d7fb..1f031c9b 100644 --- a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/DimmingFrameColorProvider.java +++ b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/DimmingFrameColorProvider.java @@ -36,6 +36,7 @@ import io.github.bric3.fireplace.core.ui.DarkLightColor; import java.awt.*; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -47,32 +48,69 @@ import static io.github.bric3.fireplace.flamegraph.FrameRenderingFlags.isHoveredSibling; import static io.github.bric3.fireplace.flamegraph.FrameRenderingFlags.isMinimapMode; +/** + * Frame color provider that supports frame dimming and hovering. + * + *

+ * This frame color provider is responsible for computing the color of a frame. + * It uses the actual frame and passes it to a basic color function + * that will apply the actual base background color to the frame. + *

+ * + *

+ * Then this base color can be altered or changed depending on the frame's + * flags. + *

+ * + * @param The actual type of frame. + */ public class DimmingFrameColorProvider implements FrameColorProvider { - public static final Color DIMMED_TEXT = new DarkLightColor( + public static final Color DIMMED_TEXT_COLOR = new DarkLightColor( Colors.rgba(28, 43, 52, 0.68f), Colors.rgba(255, 255, 255, 0.51f) ); - public static final Color HOVERED_NODE = new DarkLightColor( + public static final Color HOVERED_BACKGROUND_COLOR = new DarkLightColor( new Color(0xFFE0C268, true), new Color(0xD0E0C268, true) ); - public static final Color ROOT_NODE = new DarkLightColor( + public static final Color ROOT_BACKGROUND_COLOR = new DarkLightColor( new Color(0xFFEAF6FC), new Color(0xFF091222) ); private final Function, Color> baseColorFunction; + + /** + * Single instance to avoid too many allocations, only for the main canvas. + */ private final ColorModel reusedColorModelForMainCanvas = new ColorModel(null, null); + + /** + * Single instance to avoid too many allocations, only for the minimap. + * Since the minimap generation happens on a different thread, it is necessary + * to have a separate instance. + */ private final ColorModel reusedColorModelForMinimap = new ColorModel(null, null); private final ConcurrentHashMap dimmedColorCache = new ConcurrentHashMap<>(); + private Color rootBackGroundColor = ROOT_BACKGROUND_COLOR; + private Color dimmedTextColor = DIMMED_TEXT_COLOR; + private Color hoveredBackgroundColor = HOVERED_BACKGROUND_COLOR; + + /** + * Builds a basic frame color provider. + * + * @param baseColorFunction The color function that provides the frame's color. + * @see #withRootBackgroundColor(Color) + * @see #withDimmedTextColor(Color) + * @see #withHoveredBackgroundColor(Color) + */ public DimmingFrameColorProvider(Function, Color> baseColorFunction) { this.baseColorFunction = baseColorFunction; } - @Override public ColorModel getColors(FrameBox frame, int flags) { Color backgroundColor; @@ -80,7 +118,7 @@ public ColorModel getColors(FrameBox frame, int flags) { var rootNode = frame.isRoot(); if (rootNode) { - backgroundColor = ROOT_NODE; + backgroundColor = rootBackGroundColor; } else { backgroundColor = baseColorFunction.apply(frame); } @@ -91,14 +129,19 @@ public ColorModel getColors(FrameBox frame, int flags) { } if (!rootNode && shouldDim(flags)) { - backgroundColor = cachedDim(backgroundColor); - foreground = DIMMED_TEXT; + backgroundColor = dimmedBackground(backgroundColor); + foreground = dimmedTextColor; } else { foreground = Colors.foregroundColor(backgroundColor); } - if (isHovered(flags) || isHoveredSibling(flags)) { - backgroundColor = Colors.blend(backgroundColor, HOVERED_NODE); + if (isHovered(flags)) { + backgroundColor = hoverBackground(backgroundColor); + foreground = Colors.foregroundColor(backgroundColor); + } + + if (isHoveredSibling(flags)) { + backgroundColor = hoverSiblingBackground(backgroundColor); foreground = Colors.foregroundColor(backgroundColor); } @@ -108,6 +151,36 @@ public ColorModel getColors(FrameBox frame, int flags) { ); } + /** + * Compute the background color for a hovered frame. + * + * @param backgroundColor The background color of the frame to alter. + * @return The hovered background color. + */ + private Color hoverBackground(Color backgroundColor) { + return Colors.blend(backgroundColor, hoveredBackgroundColor); + } + + /** + * Compute the background color for a hovered sibling frame. + * + * @param backgroundColor The background color of the frame to alter. + * @return The hovered background color. + */ + private Color hoverSiblingBackground(Color backgroundColor) { + return Colors.blend(backgroundColor, hoveredBackgroundColor); + } + + /** + * Dims the background color. + * + * @param backgroundColor The background color to dim. + * @return The dimmed color. + */ + protected Color dimmedBackground(Color backgroundColor) { + return cachedDim(backgroundColor); + } + /** * Dim only if not highlighted or not focused *

@@ -137,4 +210,19 @@ private boolean shouldDim(int flags) { private Color cachedDim(Color color) { return dimmedColorCache.computeIfAbsent(color, Colors::dim); } + + public DimmingFrameColorProvider withRootBackgroundColor(Color rootBackgroundColor) { + this.rootBackGroundColor = Objects.requireNonNull(rootBackgroundColor); + return this; + } + + public DimmingFrameColorProvider withDimmedTextColor(Color dimmedTextColor) { + this.dimmedTextColor = Objects.requireNonNull(dimmedTextColor); + return this; + } + + public DimmingFrameColorProvider withHoveredBackgroundColor(Color hoveredBackgroundColor) { + this.hoveredBackgroundColor = Objects.requireNonNull(hoveredBackgroundColor); + return this; + } }