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;
+ }
}