diff --git a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphRenderEngine.java b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphRenderEngine.java index c7d6749..243f759 100644 --- a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphRenderEngine.java +++ b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphRenderEngine.java @@ -27,7 +27,7 @@ import java.util.stream.Collectors; /** - * Engine that paint a flamegraph. + * Engine that paints a flamegraph. * *

* This controls the global flamegraph rendering, and allow to @@ -185,7 +185,6 @@ public FlamegraphRenderEngine(@NotNull FrameRenderer<@NotNull T> frameRenderer) * @return The height. */ public int computeVisibleFlamegraphMinimapHeight(int thumbnailWidth) { - checkReady(); assert thumbnailWidth > 0 : "minimap width must be superior to 0"; // Somewhat it is a best-effort to draw something that shows @@ -305,7 +304,6 @@ private void internalPaint( boolean minimapMode, boolean icicle ) { - checkReady(); if (frameModel.frames.isEmpty()) { return; } @@ -515,7 +513,9 @@ public Rectangle getFrameRectangle( @NotNull Rectangle2D bounds, @NotNull Point point ) { - checkReady(); + if (frameModel.frames.isEmpty()) { + return Optional.empty(); + } int depth = computeFrameDepth(g2, bounds, point); double xLocation = point.x / bounds.getWidth(); @@ -572,7 +572,9 @@ public void hoverFrame( @NotNull Rectangle2D bounds, @NotNull Consumer<@NotNull Rectangle> hoverConsumer ) { - checkReady(); + if (frameModel.frames.isEmpty()) { + return; + } var oldHoveredFrame = hoveredFrame; if (frame == oldHoveredFrame) { @@ -595,7 +597,9 @@ public void stopHover( @NotNull Rectangle2D bounds, @NotNull Consumer<@NotNull Rectangle> hoverConsumer ) { - checkReady(); + if (frameModel.frames.isEmpty()) { + return; + } var oldHoveredFrame = hoveredFrame; var oldHoveredSiblingFrame = hoveredSiblingFrames; @@ -634,7 +638,9 @@ public void stopHover( Rectangle2D viewRect, Point point ) { - checkReady(); + if (frameModel.frames.isEmpty()) { + return Optional.empty(); + } return getFrameAt(g2, bounds, point).map(frame -> { // TODO refactor to make frame selection explicit, possibly via toggleSelectedFrameAt diff --git a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphView.java b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphView.java index 59fc47d..e76ef78 100644 --- a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphView.java +++ b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlamegraphView.java @@ -50,7 +50,7 @@ * {@link FrameBox}. *

*

- * It can be used is as follows: + * It can be used as follows: *


  * var flamegraphView = new FlamegraphView<MyNode>();
  * flamegraphView.setShowMinimap(false);
@@ -341,30 +341,24 @@ public void layoutContainer(Container parent) {
                         int oldVpWidth = oldViewPortSize.width;
                         var vpSize = vp.getSize(oldViewPortSize);
 
+                        // Never show the horizontal scrollbar when the scale factor is 1.0
+                        // Only change it when necessary
+                        int horizontalScrollBarPolicy = jScrollPane.getHorizontalScrollBarPolicy();
+                        double lastScaleFactor = canvas.zoomModel.getLastScaleFactor();
+                        int newPolicy = lastScaleFactor == 1.0 ?
+                                     ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER :
+                                     ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
+                        if (horizontalScrollBarPolicy != newPolicy) {
+                            jScrollPane.setHorizontalScrollBarPolicy(newPolicy);
+                        }
+
                         // view port has been resized
                         if (vpSize.width != oldVpWidth) {
-                            // if old fg width == old vp width
-                            //   the scaleFactor is 1.0
-                            //   => recompute the fg size
-                            // if old fg width > old vp width
-                            //   the scaleFactor is > 1.0
-                            //   => compute the scaleFactor
-                            //   => scale the fg size using the current vp width
-                            // if old fg width < old vp width
-                            //   ==> do nothing
-                            int oldFlamegraphWidth = flamegraphSize.width;
-                            if (oldFlamegraphWidth == oldVpWidth) {
-                                canvas.updateFlamegraphDimension(
-                                        flamegraphSize,
-                                        vpSize.width
-                                );
-                            } else {
-                                // scale the fg size with the new viewport width
-                                canvas.updateFlamegraphDimension(
-                                        flamegraphSize,
-                                        (int) (((double) vpSize.width) / canvas.zoomModel.getLastScaleFactor())
-                                );
-                            }
+                            // scale the fg size with the new viewport width
+                            canvas.updateFlamegraphDimension(
+                                    flamegraphSize,
+                                    (int) (((double) vpSize.width) / lastScaleFactor)
+                            );
                             vp.setViewSize(flamegraphSize);
 
                             // if view position X > 0
@@ -571,7 +565,7 @@ public boolean isShowHoveredSiblings() {
     }
 
     /**
-     * Sets the display mode, either {@link Mode#FLAMEGRAPH} or {@link Mode#ICICLEGRAPH}.
+     * Sets the display mode, either {@link FlamegraphView.Mode#FLAMEGRAPH} or {@link Mode#ICICLEGRAPH}.
      *
      * @param mode The display mode.
      */
@@ -758,7 +752,7 @@ public void requestRepaint() {
         canvas.triggerMinimapGeneration();
     }
 
-    public void overrideZoomAction(@NotNull ZoomAction zoomActionOverride) {
+    public void overrideZoomAction(@NotNull FlamegraphView.ZoomAction zoomActionOverride) {
         Objects.requireNonNull(zoomActionOverride);
         this.canvas.zoomActionOverride = zoomActionOverride;
     }
@@ -783,9 +777,9 @@ public void zoomTo(@NotNull FrameBox<@NotNull T> frame) {
      * Higher level zoom op that operates on the view and model.
      * 

* This method will call under the hood {@link FlamegraphCanvas#zoom(ZoomTarget)}. - * Possibly a zoom override ({@link #overrideZoomAction(ZoomAction)} will be set up and may be call instead, + * Possibly a zoom override ({@link #overrideZoomAction(FlamegraphView.ZoomAction)} will be set up and may be call instead, * but under the hood this will call {@link FlamegraphCanvas#zoom(ZoomTarget)} via it's - * {@link ZoomableComponent#zoom(ZoomTarget)}. + * {@link FlamegraphView.ZoomableComponent#zoom(ZoomTarget)}. * * @param canvas the canvas. * @param zoomTarget the zoom target. @@ -914,7 +908,7 @@ public void componentShown(ComponentEvent e) { // * The guard uses the hash code of the model because the model can be changed, // and running this listener is necessary to prevent the horizontal scrollbar as well. if (fgCanvas.flamegraphRenderEngine != null - && fgCanvas.flamegraphRenderEngine.getFrameModel() != null) { + && !fgCanvas.flamegraphRenderEngine.getFrameModel().frames.isEmpty()) { int newHashCode = fgCanvas.flamegraphRenderEngine.getFrameModel().hashCode(); if (newHashCode == frameModelHashCode) { return; @@ -1079,7 +1073,7 @@ private void paintDetails(@NotNull Graphics2D g2) { } private void paintMinimap(@NotNull Graphics g, @NotNull Rectangle visibleRect) { - if (flamegraphDimension != null && showMinimap && minimap != null) { + if (showMinimap && minimap != null) { var g2 = (Graphics2D) g.create( visibleRect.x + minimapBounds.x, visibleRect.y + visibleRect.height - minimapBounds.height - minimapBounds.y, @@ -1295,10 +1289,6 @@ public void mouseDragged(@NotNull MouseEvent e) { } private void processMinimapMouseEvent(@NotNull MouseEvent e) { - if (flamegraphDimension == null) { - return; - } - var pt = e.getPoint(); if (!(e.getComponent() instanceof FlamegraphView.FlamegraphCanvas)) { return; @@ -1329,7 +1319,6 @@ public void mouseMoved(@NotNull MouseEvent e) { this.addMouseListener(mouseAdapter); this.addMouseMotionListener(mouseAdapter); - // TODO Record last position after user interaction new UserPositionRecorderMouseAdapter(this).install(scrollPane); } @@ -1460,7 +1449,7 @@ public void zoom(@NotNull ZoomTarget<@NotNull T> zoomTarget) { *

* * @param - * @see HoverListener + * @see FlamegraphView.HoverListener */ private static class FlamegraphHoveringScrollPaneMouseListener implements MouseInputListener, FocusListener { private Point pressedPoint; @@ -1713,11 +1702,21 @@ private static class ZoomModel { /** * Internal field to track the last user interaction - * of the user that leads to a modification of the position ratio. - * Either the last zoom, the last mouse drag, or the last scroll (trackpad included). + * of the user that leads to a modification of the position ratio on the interval [0.0, 1.0]. + * This is also referred to as startX. + * Modified either the last zoom, the last mouse drag, or the last scroll (trackpad included). */ private double lastUserInteractionStartX = 0.0; + /** + * Internal field to track the last user interaction + * of the user that leads to a modification of the end position on the interval [0.0, 1.0]. + * This is also referred to as endX. + * Modified either the last zoom, the last mouse drag, or the last scroll (trackpad included). + */ private double lastUserInteractionEndX = 0.0; + /** + * The scale factor resulting from the last user interaction. + */ private double lastScaleFactor = 1.0; private final Rectangle canvasVisibleRect = new Rectangle(); // reused @@ -1735,7 +1734,7 @@ public void recordLastPositionFromZoomTarget( } else { lastUserInteractionStartX = currentZoomTarget.targetFrame.startX; lastUserInteractionEndX = currentZoomTarget.targetFrame.endX; - + canvas.computeVisibleRect(canvasVisibleRect); this.lastScaleFactor = FlamegraphRenderEngine.getScaleFactor( canvasVisibleRect.width,