This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch feature/CAMEL-23672-tui-diagram
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 066505e887ece4bac4166b1835283cbccea2469f
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jun 3 21:34:56 2026 +0200

    CAMEL-23672: camel-tui - Remove image diagram rendering, text-only mode
    
    Remove all image-based diagram rendering from the TUI. The TUI is text-based
    so image rendering via terminal protocols (iTerm2/Kitty/Sixel) is 
unnecessary
    complexity. This removes ~230 lines of image handling code including 
crop/scroll
    calculations, terminal capability detection, and image protocol negotiation.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../jbang/core/commands/tui/DiagramSupport.java    | 418 ++++++---------------
 .../dsl/jbang/core/commands/tui/DiagramTab.java    |  20 +-
 .../dsl/jbang/core/commands/tui/ErrorsTab.java     |  11 +-
 .../dsl/jbang/core/commands/tui/HistoryTab.java    |   5 +-
 .../dsl/jbang/core/commands/tui/RoutesTab.java     |  22 +-
 5 files changed, 122 insertions(+), 354 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
index 4b6174adea8e..0353cceb6705 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramSupport.java
@@ -25,11 +25,6 @@ import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import dev.tamboui.image.Image;
-import dev.tamboui.image.ImageData;
-import dev.tamboui.image.ImageScaling;
-import dev.tamboui.image.capability.TerminalImageCapabilities;
-import dev.tamboui.image.protocol.ImageProtocol;
 import dev.tamboui.layout.Constraint;
 import dev.tamboui.layout.Layout;
 import dev.tamboui.layout.Rect;
@@ -49,10 +44,8 @@ import dev.tamboui.widgets.scrollbar.ScrollbarState;
 import org.apache.camel.diagram.RouteDiagramAsciiRenderer;
 import org.apache.camel.diagram.RouteDiagramHelper;
 import org.apache.camel.diagram.RouteDiagramLayoutEngine;
-import org.apache.camel.diagram.RouteDiagramRenderer;
 import org.apache.camel.diagram.TopologyAsciiRenderer;
 import org.apache.camel.diagram.TopologyHelper;
-import org.apache.camel.diagram.TopologyImageRenderer;
 import org.apache.camel.diagram.TopologyLayoutEngine;
 import org.apache.camel.diagram.TopologyLayoutEngine.TopologyEdgeInfo;
 import org.apache.camel.diagram.TopologyLayoutEngine.TopologyLayoutEdge;
@@ -67,7 +60,6 @@ import static 
org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
 class DiagramSupport {
 
     private boolean showDiagram;
-    private boolean diagramTextMode;
     private boolean topologyMode;
     private boolean showDescription;
     private List<RouteDiagramAsciiRenderer.CounterPos> counterPositions = 
Collections.emptyList();
@@ -77,13 +69,6 @@ class DiagramSupport {
     private int scrollX;
     private final ScrollbarState vScrollState = new ScrollbarState();
     private final ScrollbarState hScrollState = new ScrollbarState();
-    private ImageData imageData;
-    private ImageData fullImageData;
-    private ImageProtocol protocol;
-    private int cropX = -1;
-    private int cropY = -1;
-    private int cropW = -1;
-    private int cropH = -1;
     private final AtomicBoolean loading = new AtomicBoolean(false);
     private List<TopologyAsciiRenderer.NodeBox> nodeBoxes = 
Collections.emptyList();
     private List<TopologyLayoutNode> topologyNodes = Collections.emptyList();
@@ -106,10 +91,6 @@ class DiagramSupport {
         return showDiagram;
     }
 
-    boolean isDiagramTextMode() {
-        return diagramTextMode;
-    }
-
     boolean isTopologyMode() {
         return topologyMode;
     }
@@ -178,7 +159,7 @@ class DiagramSupport {
         if (topologyLayout != null || !routeLayouts.isEmpty()) {
             return true;
         }
-        return diagramTextMode ? !lines.isEmpty() : fullImageData != null;
+        return !lines.isEmpty();
     }
 
     boolean hasNativeLayout() {
@@ -213,10 +194,6 @@ class DiagramSupport {
         return hScrollState;
     }
 
-    ImageData getFullImageData() {
-        return fullImageData;
-    }
-
     boolean handleScrollKeys(KeyEvent ke) {
         if (!showDiagram) {
             return false;
@@ -257,34 +234,14 @@ class DiagramSupport {
         return false;
     }
 
-    void toggleImageDiagram(Runnable loadTrigger) {
+    void toggleDiagram(Runnable loadTrigger) {
         if (showDiagram) {
             close();
         } else {
-            diagramTextMode = false;
             loadTrigger.run();
         }
     }
 
-    void toggleTextDiagram(Runnable loadTrigger) {
-        if (showDiagram) {
-            close();
-        } else {
-            diagramTextMode = true;
-            loadTrigger.run();
-        }
-    }
-
-    void switchToImageMode() {
-        diagramTextMode = false;
-        showDiagram = true;
-    }
-
-    void switchToTextMode() {
-        diagramTextMode = true;
-        showDiagram = true;
-    }
-
     boolean handleEscape() {
         if (showDiagram) {
             close();
@@ -295,8 +252,6 @@ class DiagramSupport {
 
     void close() {
         showDiagram = false;
-        imageData = null;
-        fullImageData = null;
     }
 
     void reset() {
@@ -316,8 +271,7 @@ class DiagramSupport {
     }
 
     void renderFooterHints(List<Span> spans) {
-        String closeKey = diagramTextMode ? "D" : "d";
-        hint(spans, closeKey + "/Esc", "close");
+        hint(spans, "Esc", "close");
         hint(spans, "↑↓←→", "scroll");
         hint(spans, "PgUp/PgDn", "page");
         hint(spans, "Home/End", "top/end");
@@ -772,7 +726,7 @@ class DiagramSupport {
         }
     }
 
-    // ---- Rendering (legacy text/image) ----
+    // ---- Rendering (legacy text) ----
 
     void renderDiagram(Frame frame, Rect area, String title) {
         Block block = Block.builder()
@@ -780,11 +734,6 @@ class DiagramSupport {
                 .title(title)
                 .build();
 
-        if (fullImageData != null) {
-            renderImageDiagram(frame, area, block);
-            return;
-        }
-
         int maxWidth = 0;
         for (String line : lines) {
             maxWidth = Math.max(maxWidth, CharWidth.of(line));
@@ -843,76 +792,6 @@ class DiagramSupport {
         }
     }
 
-    private void renderImageDiagram(Frame frame, Rect area, Block block) {
-        int imgW = fullImageData.width();
-        int imgH = fullImageData.height();
-
-        Rect inner = block.inner(area);
-        int pxPerCol = protocol.resolution().widthMultiplier();
-        int pxPerRow = protocol.resolution().heightMultiplier();
-        int viewCols = Math.max(1, inner.width() - 1);
-        int viewRows = Math.max(1, inner.height() - 1);
-        int viewW = viewCols * pxPerCol;
-        int viewH = viewRows * pxPerRow;
-
-        int maxScrollY = Math.max(0, (imgH - viewH + pxPerRow - 1) / pxPerRow);
-        int maxScrollX = Math.max(0, (imgW - viewW + pxPerCol - 1) / pxPerCol);
-        scrollY = Math.min(scrollY, maxScrollY);
-        scrollX = Math.min(scrollX, maxScrollX);
-
-        int cx = Math.min(scrollX * pxPerCol, imgW);
-        int cy = Math.min(scrollY * pxPerRow, imgH);
-        int cw = Math.min(viewW, imgW - cx);
-        int ch = Math.min(viewH, imgH - cy);
-
-        if (cw > 0 && ch > 0) {
-            if (cx != cropX || cy != cropY || cw != cropW || ch != cropH) {
-                imageData = fullImageData.crop(cx, cy, cw, ch);
-                cropX = cx;
-                cropY = cy;
-                cropW = cw;
-                cropH = ch;
-            }
-        } else if (imageData != fullImageData) {
-            imageData = fullImageData;
-        }
-
-        frame.renderWidget(block, area);
-
-        List<Rect> vChunks = Layout.vertical()
-                .constraints(Constraint.fill(), Constraint.length(1))
-                .split(inner);
-
-        List<Rect> hChunks = Layout.horizontal()
-                .constraints(Constraint.fill(), Constraint.length(1))
-                .split(vChunks.get(0));
-
-        Image img = Image.builder()
-                .data(imageData)
-                .protocol(protocol)
-                .scaling(ImageScaling.FIT)
-                .build();
-        frame.renderWidget(img, hChunks.get(0));
-
-        int totalRows = (imgH + pxPerRow - 1) / pxPerRow;
-        vScrollState.contentLength(totalRows);
-        vScrollState.viewportContentLength(viewRows);
-        vScrollState.position(scrollY);
-        frame.renderStatefulWidget(
-                Scrollbar.builder().build(),
-                hChunks.get(1), vScrollState);
-
-        if (imgW > viewW) {
-            int totalCols = (imgW + pxPerCol - 1) / pxPerCol;
-            hScrollState.contentLength(totalCols);
-            hScrollState.viewportContentLength(viewCols);
-            hScrollState.position(scrollX);
-            frame.renderStatefulWidget(
-                    Scrollbar.horizontal(),
-                    vChunks.get(1), hScrollState);
-        }
-    }
-
     // ---- Async loading ----
 
     boolean beginLoad() {
@@ -925,19 +804,17 @@ class DiagramSupport {
 
     void setLoadingPlaceholder() {
         lines = List.of("(Loading diagram...)");
-        imageData = null;
-        fullImageData = null;
         showDiagram = true;
         scrollY = 0;
         scrollX = 0;
     }
 
     void loadHighlightedDiagramInBackground(
-            MonitorContext ctx, String pid, boolean textMode,
+            MonitorContext ctx, String pid,
             String[] messageHistory, RouteDiagramHelper.HighlightStyle 
hlStyle) {
         JsonObject jo = requestRouteStructure(ctx, pid);
         if (jo == null) {
-            applyResult(ctx, List.of("(No response from integration)"), null, 
null, null);
+            applyResult(ctx, List.of("(No response from integration)"));
             return;
         }
 
@@ -947,7 +824,7 @@ class DiagramSupport {
 
         List<RouteDiagramLayoutEngine.RouteInfo> routes = 
RouteDiagramHelper.parseRoutes(jo);
         if (routes.isEmpty()) {
-            applyResult(ctx, List.of("(No routes in response)"), null, null, 
null);
+            applyResult(ctx, List.of("(No routes in response)"));
             return;
         }
 
@@ -962,11 +839,11 @@ class DiagramSupport {
                 = new RouteDiagramHelper.HighlightInfo(nodeIds, 
highlightInfo.getRouteOrder(), hlStyle);
         routes = RouteDiagramHelper.filterAndOrderRoutes(routes, 
fullHighlight);
         if (routes.isEmpty()) {
-            applyResult(ctx, List.of("(No routes contain highlighted nodes)"), 
null, null, null);
+            applyResult(ctx, List.of("(No routes contain highlighted nodes)"));
             return;
         }
 
-        renderRoutes(ctx, textMode, routes, false, nodeIds, hlStyle);
+        renderRoutes(ctx, routes, false, nodeIds, hlStyle);
     }
 
     void loadAllDiagramsInBackground(
@@ -1063,17 +940,17 @@ class DiagramSupport {
     }
 
     void loadRouteDiagramInBackground(
-            MonitorContext ctx, String pid, boolean textMode,
+            MonitorContext ctx, String pid,
             String routeId, boolean metrics) {
         JsonObject jo = requestRouteStructure(ctx, pid);
         if (jo == null) {
-            applyResult(ctx, List.of("(No response from integration)"), null, 
null, null);
+            applyResult(ctx, List.of("(No response from integration)"));
             return;
         }
 
         List<RouteDiagramLayoutEngine.RouteInfo> routes = 
RouteDiagramHelper.parseRoutes(jo);
         if (routes.isEmpty()) {
-            applyResult(ctx, List.of("(No routes in response)"), null, null, 
null);
+            applyResult(ctx, List.of("(No routes in response)"));
             return;
         }
 
@@ -1081,14 +958,14 @@ class DiagramSupport {
             routes.removeIf(r -> !routeId.equals(r.routeId));
         }
 
-        renderRoutes(ctx, textMode, routes, metrics, null, null);
+        renderRoutes(ctx, routes, metrics, null, null);
     }
 
     void loadTopologyDiagramInBackground(
-            MonitorContext ctx, String pid, boolean textMode, boolean metrics, 
boolean external) {
+            MonitorContext ctx, String pid, boolean metrics, boolean external) 
{
         JsonObject jo = requestRouteTopology(ctx, pid, external, false);
         if (jo == null) {
-            applyResult(ctx, List.of("(No response from integration)"), null, 
null, null);
+            applyResult(ctx, List.of("(No response from integration)"));
             return;
         }
 
@@ -1098,77 +975,58 @@ class DiagramSupport {
             TopologyHelper.addExternalEndpoints(nodes, edges, jo);
         }
         if (nodes.isEmpty()) {
-            applyResult(ctx, List.of("(No routes in response)"), null, null, 
null);
+            applyResult(ctx, List.of("(No routes in response)"));
             return;
         }
 
         TopologyLayoutEngine engine = new TopologyLayoutEngine();
         TopologyLayoutResult result = engine.layout(nodes, edges);
 
-        if (textMode) {
-            TopologyAsciiRenderer renderer = new TopologyAsciiRenderer(
-                    engine.getNodeWidth(), true, metrics, showDescription);
-            String text = renderer.renderDiagramPlain(result);
-
-            List<String> resultLines = new ArrayList<>();
-            List<RouteDiagramAsciiRenderer.CounterPos> positions = new 
ArrayList<>();
-            String[] rawLines = text.split("\n", -1);
-            int[] rowMapping = new int[rawLines.length];
-            int newRow = 0;
-            for (int i = 0; i < rawLines.length; i++) {
-                if (!rawLines[i].isEmpty()) {
-                    rowMapping[i] = newRow++;
-                    resultLines.add(rawLines[i]);
-                } else {
-                    rowMapping[i] = -1;
-                }
-            }
-
-            for (TopologyAsciiRenderer.CounterPos cp : 
renderer.getCounterPositions()) {
-                if (cp.row() >= 0 && cp.row() < rowMapping.length && 
rowMapping[cp.row()] >= 0) {
-                    RouteDiagramAsciiRenderer.CounterType mapped = switch 
(cp.type()) {
-                        case OK -> RouteDiagramAsciiRenderer.CounterType.OK;
-                        case FAIL -> 
RouteDiagramAsciiRenderer.CounterType.FAIL;
-                        case TRIGGER -> 
RouteDiagramAsciiRenderer.CounterType.HIGHLIGHT_SUCCESS;
-                        case EXTERNAL -> 
RouteDiagramAsciiRenderer.CounterType.EXTERNAL;
-                    };
-                    positions.add(new RouteDiagramAsciiRenderer.CounterPos(
-                            rowMapping[cp.row()], cp.col(), cp.length(), 
mapped));
-                }
+        TopologyAsciiRenderer renderer = new TopologyAsciiRenderer(
+                engine.getNodeWidth(), true, metrics, showDescription);
+        String text = renderer.renderDiagramPlain(result);
+
+        List<String> resultLines = new ArrayList<>();
+        List<RouteDiagramAsciiRenderer.CounterPos> positions = new 
ArrayList<>();
+        String[] rawLines = text.split("\n", -1);
+        int[] rowMapping = new int[rawLines.length];
+        int newRow = 0;
+        for (int i = 0; i < rawLines.length; i++) {
+            if (!rawLines[i].isEmpty()) {
+                rowMapping[i] = newRow++;
+                resultLines.add(rawLines[i]);
+            } else {
+                rowMapping[i] = -1;
             }
+        }
 
-            List<TopologyAsciiRenderer.NodeBox> boxes = new ArrayList<>();
-            for (TopologyAsciiRenderer.NodeBox nb : renderer.getNodeBoxes()) {
-                int mappedStart = (nb.startRow() >= 0 && nb.startRow() < 
rowMapping.length)
-                        ? rowMapping[nb.startRow()] : -1;
-                int mappedEnd = (nb.endRow() >= 0 && nb.endRow() < 
rowMapping.length)
-                        ? rowMapping[nb.endRow()] : -1;
-                if (mappedStart >= 0 && mappedEnd >= 0) {
-                    boxes.add(new TopologyAsciiRenderer.NodeBox(
-                            nb.routeId(), mappedStart, mappedEnd, 
nb.startCol(), nb.endCol(), nb.layer()));
-                }
+        for (TopologyAsciiRenderer.CounterPos cp : 
renderer.getCounterPositions()) {
+            if (cp.row() >= 0 && cp.row() < rowMapping.length && 
rowMapping[cp.row()] >= 0) {
+                RouteDiagramAsciiRenderer.CounterType mapped = switch 
(cp.type()) {
+                    case OK -> RouteDiagramAsciiRenderer.CounterType.OK;
+                    case FAIL -> RouteDiagramAsciiRenderer.CounterType.FAIL;
+                    case TRIGGER -> 
RouteDiagramAsciiRenderer.CounterType.HIGHLIGHT_SUCCESS;
+                    case EXTERNAL -> 
RouteDiagramAsciiRenderer.CounterType.EXTERNAL;
+                };
+                positions.add(new RouteDiagramAsciiRenderer.CounterPos(
+                        rowMapping[cp.row()], cp.col(), cp.length(), mapped));
             }
+        }
 
-            applyResult(ctx, resultLines, null, null, null, positions, 
Collections.emptySet(), boxes,
-                    result.nodes, result.edges);
-        } else {
-            TerminalImageCapabilities caps = 
TerminalImageCapabilities.detect();
-            if (caps.supportsNativeImages()) {
-                RouteDiagramRenderer.DiagramColors colors
-                        = 
RouteDiagramRenderer.DiagramColors.parse("transparent");
-                java.awt.image.BufferedImage image = 
TopologyImageRenderer.renderImage(
-                        result, colors, TopologyLayoutEngine.DEFAULT_FONT_SIZE,
-                        TopologyLayoutEngine.DEFAULT_NODE_WIDTH, metrics, 
false);
-                ImageData full = ImageData.fromBufferedImage(image);
-                ImageData resized = full.resize(full.width() / 2, 
full.height() / 2);
-                ImageProtocol proto = caps.bestProtocol();
-                applyResult(ctx, Collections.emptyList(), resized, resized, 
proto);
-            } else {
-                applyResult(ctx, List.of(
-                        "(Terminal does not support image rendering)",
-                        "(Press Shift+D for text diagram)"), null, null, null);
+        List<TopologyAsciiRenderer.NodeBox> boxes = new ArrayList<>();
+        for (TopologyAsciiRenderer.NodeBox nb : renderer.getNodeBoxes()) {
+            int mappedStart = (nb.startRow() >= 0 && nb.startRow() < 
rowMapping.length)
+                    ? rowMapping[nb.startRow()] : -1;
+            int mappedEnd = (nb.endRow() >= 0 && nb.endRow() < 
rowMapping.length)
+                    ? rowMapping[nb.endRow()] : -1;
+            if (mappedStart >= 0 && mappedEnd >= 0) {
+                boxes.add(new TopologyAsciiRenderer.NodeBox(
+                        nb.routeId(), mappedStart, mappedEnd, nb.startCol(), 
nb.endCol(), nb.layer()));
             }
         }
+
+        applyResult(ctx, resultLines, positions, Collections.emptySet(), boxes,
+                result.nodes, result.edges);
     }
 
     private JsonObject requestRouteTopology(MonitorContext ctx, String pid, 
boolean external, boolean routes) {
@@ -1194,98 +1052,65 @@ class DiagramSupport {
     }
 
     private void renderRoutes(
-            MonitorContext ctx, boolean textMode,
+            MonitorContext ctx,
             List<RouteDiagramLayoutEngine.RouteInfo> routes, boolean metrics,
             Set<String> highlightNodeIds, RouteDiagramHelper.HighlightStyle 
hlStyle) {
-        if (textMode) {
-            RouteDiagramLayoutEngine.NodeLabelMode labelMode = showDescription
-                    ? RouteDiagramLayoutEngine.NodeLabelMode.DESCRIPTION
-                    : RouteDiagramLayoutEngine.NodeLabelMode.CODE;
-            RouteDiagramLayoutEngine engine = new RouteDiagramLayoutEngine(
-                    RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH, 
RouteDiagramLayoutEngine.DEFAULT_FONT_SIZE,
-                    labelMode);
-
-            List<String> result = new ArrayList<>();
-            List<RouteDiagramAsciiRenderer.CounterPos> positions = new 
ArrayList<>();
-            Set<Integer> titleRows = new HashSet<>();
-
-            int currentY = RouteDiagramLayoutEngine.PADDING;
-            for (RouteDiagramLayoutEngine.RouteInfo r : routes) {
-                if (!result.isEmpty()) {
-                    result.add("");
-                    result.add("");
-                }
+        RouteDiagramLayoutEngine.NodeLabelMode labelMode = showDescription
+                ? RouteDiagramLayoutEngine.NodeLabelMode.DESCRIPTION
+                : RouteDiagramLayoutEngine.NodeLabelMode.CODE;
+        RouteDiagramLayoutEngine engine = new RouteDiagramLayoutEngine(
+                RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH, 
RouteDiagramLayoutEngine.DEFAULT_FONT_SIZE,
+                labelMode);
+
+        List<String> result = new ArrayList<>();
+        List<RouteDiagramAsciiRenderer.CounterPos> positions = new 
ArrayList<>();
+        Set<Integer> titleRows = new HashSet<>();
+
+        int currentY = RouteDiagramLayoutEngine.PADDING;
+        for (RouteDiagramLayoutEngine.RouteInfo r : routes) {
+            if (!result.isEmpty()) {
+                result.add("");
+                result.add("");
+            }
 
-                int titleRow = result.size();
+            int titleRow = result.size();
 
-                RouteDiagramLayoutEngine.LayoutRoute lr = 
engine.layoutRoute(r, currentY);
-                currentY = lr.maxY + RouteDiagramLayoutEngine.V_GAP;
+            RouteDiagramLayoutEngine.LayoutRoute lr = engine.layoutRoute(r, 
currentY);
+            currentY = lr.maxY + RouteDiagramLayoutEngine.V_GAP;
 
-                RouteDiagramAsciiRenderer asciiRenderer = new 
RouteDiagramAsciiRenderer(
-                        RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH * 
RouteDiagramLayoutEngine.SCALE, true, metrics);
-                String ascii;
-                if (highlightNodeIds != null && hlStyle != null) {
-                    ascii = asciiRenderer.renderDiagram(List.of(lr),
-                            lr.maxY + RouteDiagramLayoutEngine.V_GAP, 
highlightNodeIds, hlStyle);
-                } else {
-                    ascii = asciiRenderer.renderDiagram(List.of(lr),
-                            lr.maxY + RouteDiagramLayoutEngine.V_GAP);
-                }
-                List<RouteDiagramAsciiRenderer.CounterPos> origPositions = 
asciiRenderer.getCounterPositions();
-
-                String[] rawLines = ascii.split("\n", -1);
-                int[] rowMapping = new int[rawLines.length];
-                int newRow = result.size();
-                for (int i = 0; i < rawLines.length; i++) {
-                    if (!rawLines[i].isEmpty()) {
-                        rowMapping[i] = newRow++;
-                        result.add(rawLines[i]);
-                    } else {
-                        rowMapping[i] = -1;
-                    }
-                }
-                for (RouteDiagramAsciiRenderer.CounterPos cp : origPositions) {
-                    if (cp.row() >= 0 && cp.row() < rowMapping.length && 
rowMapping[cp.row()] >= 0) {
-                        positions.add(new RouteDiagramAsciiRenderer.CounterPos(
-                                rowMapping[cp.row()], cp.col(), cp.length(), 
cp.type()));
-                    }
-                }
-                titleRows.add(titleRow);
+            RouteDiagramAsciiRenderer asciiRenderer = new 
RouteDiagramAsciiRenderer(
+                    RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH * 
RouteDiagramLayoutEngine.SCALE, true, metrics);
+            String ascii;
+            if (highlightNodeIds != null && hlStyle != null) {
+                ascii = asciiRenderer.renderDiagram(List.of(lr),
+                        lr.maxY + RouteDiagramLayoutEngine.V_GAP, 
highlightNodeIds, hlStyle);
+            } else {
+                ascii = asciiRenderer.renderDiagram(List.of(lr),
+                        lr.maxY + RouteDiagramLayoutEngine.V_GAP);
             }
+            List<RouteDiagramAsciiRenderer.CounterPos> origPositions = 
asciiRenderer.getCounterPositions();
 
-            applyResult(ctx, result, null, null, null, positions, titleRows);
-        } else {
-            TerminalImageCapabilities caps = 
TerminalImageCapabilities.detect();
-            if (caps.supportsNativeImages()) {
-                RouteDiagramLayoutEngine engine = new 
RouteDiagramLayoutEngine();
-                List<RouteDiagramLayoutEngine.LayoutRoute> layoutRoutes = new 
ArrayList<>();
-                int totalHeight = 0;
-                for (RouteDiagramLayoutEngine.RouteInfo r : routes) {
-                    RouteDiagramLayoutEngine.LayoutRoute lr = 
engine.layoutRoute(r, totalHeight);
-                    layoutRoutes.add(lr);
-                    totalHeight = lr.maxY;
-                }
-                RouteDiagramRenderer renderer = new RouteDiagramRenderer(
-                        engine.getNodeWidth(),
-                        RouteDiagramLayoutEngine.DEFAULT_FONT_SIZE * 
RouteDiagramLayoutEngine.SCALE, metrics);
-                RouteDiagramRenderer.DiagramColors colors
-                        = 
RouteDiagramRenderer.DiagramColors.parse("transparent");
-                java.awt.image.BufferedImage image;
-                if (highlightNodeIds != null && hlStyle != null) {
-                    image = renderer.renderDiagram(layoutRoutes, totalHeight, 
colors, highlightNodeIds, hlStyle);
+            String[] rawLines = ascii.split("\n", -1);
+            int[] rowMapping = new int[rawLines.length];
+            int newRow = result.size();
+            for (int i = 0; i < rawLines.length; i++) {
+                if (!rawLines[i].isEmpty()) {
+                    rowMapping[i] = newRow++;
+                    result.add(rawLines[i]);
                 } else {
-                    image = renderer.renderDiagram(layoutRoutes, totalHeight, 
colors);
+                    rowMapping[i] = -1;
                 }
-                ImageData full = ImageData.fromBufferedImage(image);
-                ImageData resized = full.resize(full.width() / 2, 
full.height() / 2);
-                ImageProtocol proto = caps.bestProtocol();
-                applyResult(ctx, Collections.emptyList(), resized, resized, 
proto);
-            } else {
-                applyResult(ctx, List.of(
-                        "(Terminal does not support image rendering)",
-                        "(Press Shift+D for text diagram)"), null, null, null);
             }
+            for (RouteDiagramAsciiRenderer.CounterPos cp : origPositions) {
+                if (cp.row() >= 0 && cp.row() < rowMapping.length && 
rowMapping[cp.row()] >= 0) {
+                    positions.add(new RouteDiagramAsciiRenderer.CounterPos(
+                            rowMapping[cp.row()], cp.col(), cp.length(), 
cp.type()));
+                }
+            }
+            titleRows.add(titleRow);
         }
+
+        applyResult(ctx, result, positions, titleRows);
     }
 
     private JsonObject requestRouteStructure(MonitorContext ctx, String pid) {
@@ -1306,29 +1131,20 @@ class DiagramSupport {
         return jo;
     }
 
-    private void applyResult(
-            MonitorContext ctx,
-            List<String> resultLines, ImageData resultImageData, ImageData 
resultFullImageData,
-            ImageProtocol resultProtocol) {
-        applyResult(ctx, resultLines, resultImageData, resultFullImageData, 
resultProtocol,
-                Collections.emptyList(), Collections.emptySet(), 
Collections.emptyList(),
-                Collections.emptyList(), Collections.emptyList());
+    private void applyResult(MonitorContext ctx, List<String> resultLines) {
+        applyResult(ctx, resultLines, Collections.emptyList(), 
Collections.emptySet(),
+                Collections.emptyList(), Collections.emptyList(), 
Collections.emptyList());
     }
 
     private void applyResult(
-            MonitorContext ctx,
-            List<String> resultLines, ImageData resultImageData, ImageData 
resultFullImageData,
-            ImageProtocol resultProtocol,
+            MonitorContext ctx, List<String> resultLines,
             List<RouteDiagramAsciiRenderer.CounterPos> positions, Set<Integer> 
titleRows) {
-        applyResult(ctx, resultLines, resultImageData, resultFullImageData, 
resultProtocol,
-                positions, titleRows, Collections.emptyList(),
-                Collections.emptyList(), Collections.emptyList());
+        applyResult(ctx, resultLines, positions, titleRows,
+                Collections.emptyList(), Collections.emptyList(), 
Collections.emptyList());
     }
 
     private void applyResult(
-            MonitorContext ctx,
-            List<String> resultLines, ImageData resultImageData, ImageData 
resultFullImageData,
-            ImageProtocol resultProtocol,
+            MonitorContext ctx, List<String> resultLines,
             List<RouteDiagramAsciiRenderer.CounterPos> positions, Set<Integer> 
titleRows,
             List<TopologyAsciiRenderer.NodeBox> resultNodeBoxes,
             List<TopologyLayoutNode> resultTopologyNodes,
@@ -1341,8 +1157,6 @@ class DiagramSupport {
             lines = resultLines;
             counterPositions = positions;
             routeTitleRows = titleRows;
-            fullImageData = resultFullImageData;
-            protocol = resultProtocol;
             topologyNodes = resultTopologyNodes;
             topologyEdges = resultTopologyEdges;
 
@@ -1369,20 +1183,10 @@ class DiagramSupport {
             }
 
             if (!wasShowing) {
-                imageData = resultImageData;
                 scrollY = 0;
                 scrollX = 0;
-                cropX = -1;
-                cropY = -1;
-                cropW = -1;
-                cropH = -1;
-            } else {
-                showDiagram = true;
-                cropX = -1;
-                cropY = -1;
-                cropW = -1;
-                cropH = -1;
             }
+            showDiagram = true;
         });
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
index af4d2e6db5e8..c9b7f1a15211 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DiagramTab.java
@@ -241,17 +241,6 @@ class DiagramTab implements MonitorTab {
                 } else {
                     diagram.renderNativeRouteDiagram(frame, area, title, 
diagramMetrics, routeLayout);
                 }
-            } else {
-                if (selectedRouteId != null && area.width() > 60) {
-                    int panelWidth = 30;
-                    List<Rect> hChunks = Layout.horizontal()
-                            .constraints(Constraint.length(panelWidth), 
Constraint.fill())
-                            .split(area);
-                    renderInfoPanel(frame, hChunks.get(0), info, 
selectedRouteId);
-                    diagram.renderDiagram(frame, hChunks.get(1), title);
-                } else {
-                    diagram.renderDiagram(frame, area, title);
-                }
             }
             return;
         }
@@ -508,13 +497,8 @@ class DiagramTab implements MonitorTab {
 
         ctx.runner.scheduler().execute(() -> {
             try {
-                if (topologyMode) {
-                    diagram.setTopologyMode(true);
-                    diagram.loadAllDiagramsInBackground(ctx, pid, showMetrics, 
external);
-                } else {
-                    diagram.setTopologyMode(false);
-                    diagram.loadRouteDiagramInBackground(ctx, pid, true, 
drillDownRouteId, showMetrics);
-                }
+                diagram.setTopologyMode(topologyMode);
+                diagram.loadAllDiagramsInBackground(ctx, pid, showMetrics, 
external);
             } finally {
                 diagram.endLoad();
             }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
index b6acc9c6ff05..d2fac7eac9e0 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ErrorsTab.java
@@ -83,12 +83,8 @@ class ErrorsTab implements MonitorTab {
             return true;
         }
 
-        if (ke.isChar('d')) {
-            diagram.toggleImageDiagram(this::loadDiagramForSelectedError);
-            return true;
-        }
-        if (ke.isChar('D')) {
-            diagram.toggleTextDiagram(this::loadDiagramForSelectedError);
+        if (ke.isCharIgnoreCase('d')) {
+            diagram.toggleDiagram(this::loadDiagramForSelectedError);
             return true;
         }
 
@@ -436,7 +432,6 @@ class ErrorsTab implements MonitorTab {
         }
 
         String pid = ctx.selectedPid;
-        boolean textMode = diagram.isDiagramTextMode();
         String[] messageHistory = selectedError.messageHistory;
 
         diagram.setLoadingPlaceholder();
@@ -444,7 +439,7 @@ class ErrorsTab implements MonitorTab {
         ctx.runner.scheduler().execute(() -> {
             try {
                 diagram.loadHighlightedDiagramInBackground(
-                        ctx, pid, textMode, messageHistory, 
RouteDiagramHelper.HighlightStyle.FAIL);
+                        ctx, pid, messageHistory, 
RouteDiagramHelper.HighlightStyle.FAIL);
             } finally {
                 diagram.endLoad();
             }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
index 0a3053303ac2..9952e4b02dd8 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/HistoryTab.java
@@ -111,7 +111,7 @@ class HistoryTab implements MonitorTab {
             return true;
         }
         if (ke.isCharIgnoreCase('d')) {
-            diagram.toggleTextDiagram(this::loadDiagramForCurrentView);
+            diagram.toggleDiagram(this::loadDiagramForCurrentView);
             return true;
         }
 
@@ -495,7 +495,6 @@ class HistoryTab implements MonitorTab {
         }
 
         String pid = ctx.selectedPid;
-        boolean textMode = diagram.isDiagramTextMode();
         RouteDiagramHelper.HighlightStyle style = failed
                 ? RouteDiagramHelper.HighlightStyle.FAIL
                 : RouteDiagramHelper.HighlightStyle.SUCCESS;
@@ -504,7 +503,7 @@ class HistoryTab implements MonitorTab {
 
         ctx.runner.scheduler().execute(() -> {
             try {
-                diagram.loadHighlightedDiagramInBackground(ctx, pid, textMode, 
messageHistory, style);
+                diagram.loadHighlightedDiagramInBackground(ctx, pid, 
messageHistory, style);
             } finally {
                 diagram.endLoad();
             }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
index 8fcf67c03807..2fa9976b70ba 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RoutesTab.java
@@ -22,7 +22,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import dev.tamboui.image.ImageData;
 import dev.tamboui.layout.Constraint;
 import dev.tamboui.layout.Layout;
 import dev.tamboui.layout.Rect;
@@ -102,10 +101,6 @@ class RoutesTab implements MonitorTab {
         return diagram.isShowDiagram();
     }
 
-    boolean isDiagramTextMode() {
-        return diagram.isDiagramTextMode();
-    }
-
     boolean isDiagramMetrics() {
         return diagramMetrics;
     }
@@ -118,14 +113,6 @@ class RoutesTab implements MonitorTab {
         return showSource;
     }
 
-    ImageData getDiagramFullImageData() {
-        return diagram.getFullImageData();
-    }
-
-    boolean hasImageDiagram() {
-        return diagram.getFullImageData() != null;
-    }
-
     @Override
     public boolean handleKeyEvent(KeyEvent ke) {
         // Source view scrolling
@@ -208,7 +195,7 @@ class RoutesTab implements MonitorTab {
 
         // Text diagram toggle
         if (ke.isCharIgnoreCase('d')) {
-            diagram.toggleTextDiagram(this::loadDiagramForSelectedRoute);
+            diagram.toggleDiagram(this::loadDiagramForSelectedRoute);
             return true;
         }
 
@@ -296,7 +283,7 @@ class RoutesTab implements MonitorTab {
 
         // Fullscreen diagram mode
         if (diagram.isShowDiagram() && diagram.hasDiagramData()) {
-            String title = diagram.isDiagramTextMode() ? "" : " Diagram [" + 
diagramRouteId + "] ";
+            String title = " Diagram [" + diagramRouteId + "] ";
             if (diagramAllRoutes) {
                 diagram.renderDiagram(frame, area, title);
             } else {
@@ -447,7 +434,7 @@ class RoutesTab implements MonitorTab {
 
         // Bottom panel: diagram or processors
         if (diagram.isShowDiagram() && diagram.hasDiagramData()) {
-            String title = diagram.isDiagramTextMode() ? "" : " Diagram [" + 
diagramRouteId + "] ";
+            String title = " Diagram [" + diagramRouteId + "] ";
             diagram.renderDiagram(frame, chunks.get(1), title);
         } else {
             Integer selectedRoute = routeTableState.selected();
@@ -1002,7 +989,6 @@ class RoutesTab implements MonitorTab {
         }
 
         String pid = ctx.selectedPid;
-        boolean textMode = diagram.isDiagramTextMode();
         boolean showMetrics = diagramMetrics;
         String routeId = diagramAllRoutes ? null : selectedRoute.routeId;
 
@@ -1013,7 +999,7 @@ class RoutesTab implements MonitorTab {
 
         ctx.runner.scheduler().execute(() -> {
             try {
-                diagram.loadRouteDiagramInBackground(ctx, pid, textMode, 
routeId, showMetrics);
+                diagram.loadRouteDiagramInBackground(ctx, pid, routeId, 
showMetrics);
             } finally {
                 diagram.endLoad();
             }


Reply via email to