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

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

commit ed0c9e671419313cf3363d3567b886dcb81ad580
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed May 13 13:38:48 2026 +0200

    CAMEL-23420: Fullscreen text diagram with scrollbars in TUI monitor
    
    Co-Authored-By: Claude Opus 4.7 <[email protected]>
---
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  | 86 ++++++++++++++++++++--
 1 file changed, 79 insertions(+), 7 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index e43b721c65a1..2eea5136e72c 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
@@ -66,6 +66,8 @@ import dev.tamboui.widgets.block.Block;
 import dev.tamboui.widgets.block.BorderType;
 import dev.tamboui.widgets.gauge.Gauge;
 import dev.tamboui.widgets.paragraph.Paragraph;
+import dev.tamboui.widgets.scrollbar.Scrollbar;
+import dev.tamboui.widgets.scrollbar.ScrollbarState;
 import dev.tamboui.widgets.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
@@ -172,6 +174,9 @@ public class CamelMonitor extends CamelCommand {
     private boolean diagramTextMode;
     private List<String> diagramLines = Collections.emptyList();
     private int diagramScroll;
+    private int diagramScrollX;
+    private final ScrollbarState diagramVScrollState = new ScrollbarState();
+    private final ScrollbarState diagramHScrollState = new ScrollbarState();
     private String diagramRouteId;
     private ImageData diagramImageData;
     private ImageProtocol diagramProtocol;
@@ -315,6 +320,18 @@ public class CamelMonitor extends CamelCommand {
                 }
                 return true;
             }
+            if (ke.isLeft()) {
+                if (showDiagram && diagramImageData == null && tab == 
TAB_ROUTES) {
+                    diagramScrollX = Math.max(0, diagramScrollX - 1);
+                    return true;
+                }
+            }
+            if (ke.isRight()) {
+                if (showDiagram && diagramImageData == null && tab == 
TAB_ROUTES) {
+                    diagramScrollX++;
+                    return true;
+                }
+            }
 
             // Enter to drill into selected integration
             if (ke.isKey(KeyCode.ENTER) && tab == TAB_OVERVIEW) {
@@ -694,6 +711,12 @@ public class CamelMonitor extends CamelCommand {
             return;
         }
 
+        // Fullscreen text diagram mode
+        if (showDiagram && diagramTextMode && !diagramLines.isEmpty()) {
+            renderDiagram(frame, area);
+            return;
+        }
+
         // Sort routes
         List<RouteInfo> sortedRoutes = new ArrayList<>(info.routes);
         sortedRoutes.sort(this::sortRoute);
@@ -859,23 +882,71 @@ public class CamelMonitor extends CamelCommand {
             return;
         }
 
+        // Compute max width for horizontal scrolling
+        int maxWidth = 0;
+        for (String line : diagramLines) {
+            maxWidth = Math.max(maxWidth, line.length());
+        }
+
         Rect inner = block.inner(area);
-        int visibleLines = inner.height();
-        int maxScroll = Math.max(0, diagramLines.size() - visibleLines);
-        diagramScroll = Math.min(diagramScroll, maxScroll);
+        // Reserve 1 col for vertical scrollbar, 1 row for horizontal scrollbar
+        int visibleLines = Math.max(1, inner.height() - 1);
+        int visibleCols = Math.max(1, inner.width() - 1);
+
+        int maxVScroll = Math.max(0, diagramLines.size() - visibleLines);
+        int maxHScroll = Math.max(0, maxWidth - visibleCols);
+        diagramScroll = Math.min(diagramScroll, maxVScroll);
+        diagramScrollX = Math.min(diagramScrollX, maxHScroll);
 
+        // Build visible lines with horizontal offset applied
         List<Line> lines = new ArrayList<>();
         int end = Math.min(diagramScroll + visibleLines, diagramLines.size());
         for (int i = diagramScroll; i < end; i++) {
-            lines.add(styleDiagramLine(diagramLines.get(i)));
+            String line = diagramLines.get(i);
+            if (diagramScrollX > 0) {
+                line = diagramScrollX < line.length() ? 
line.substring(diagramScrollX) : "";
+            }
+            lines.add(styleDiagramLine(line));
         }
 
+        // Layout: outer block wraps everything, inner splits content + 
scrollbars
+        frame.renderWidget(block, area);
+
+        // Vertical layout inside the block: [content row (fill), horizontal 
scrollbar (1 row)]
+        List<Rect> vChunks = Layout.vertical()
+                .constraints(Constraint.fill(), Constraint.length(1))
+                .split(inner);
+
+        // Horizontal layout for content row: [text (fill), vertical scrollbar 
(1 col)]
+        List<Rect> hChunks = Layout.horizontal()
+                .constraints(Constraint.fill(), Constraint.length(1))
+                .split(vChunks.get(0));
+
+        // Render diagram text
         Paragraph paragraph = Paragraph.builder()
                 .text(Text.from(lines))
-                .block(block)
                 .build();
+        frame.renderWidget(paragraph, hChunks.get(0));
+
+        // Render vertical scrollbar
+        diagramVScrollState.contentLength(diagramLines.size());
+        diagramVScrollState.viewportContentLength(visibleLines);
+        diagramVScrollState.position(diagramScroll);
+        frame.renderStatefulWidget(
+                Scrollbar.builder()
+                        .thumbStyle(Style.create().fg(Color.rgb(0xF6, 0x91, 
0x23)))
+                        .build(),
+                hChunks.get(1), diagramVScrollState);
 
-        frame.renderWidget(paragraph, area);
+        // Render horizontal scrollbar
+        if (maxWidth > visibleCols) {
+            diagramHScrollState.contentLength(maxWidth);
+            diagramHScrollState.viewportContentLength(visibleCols);
+            diagramHScrollState.position(diagramScrollX);
+            frame.renderStatefulWidget(
+                    Scrollbar.horizontal(),
+                    vChunks.get(1), diagramHScrollState);
+        }
     }
 
     private Line styleDiagramLine(String text) {
@@ -1011,6 +1082,7 @@ public class CamelMonitor extends CamelCommand {
 
         diagramRouteId = selectedRoute.routeId;
         diagramScroll = 0;
+        diagramScrollX = 0;
 
         if (diagramTextMode) {
             diagramImageData = null;
@@ -1680,7 +1752,7 @@ public class CamelMonitor extends CamelCommand {
                         Span.raw("/"),
                         Span.styled("Esc", 
Style.create().fg(Color.YELLOW).bold()),
                         Span.raw(" close  "),
-                        Span.styled("\u2191\u2193", 
Style.create().fg(Color.YELLOW).bold()),
+                        Span.styled("\u2191\u2193\u2190\u2192", 
Style.create().fg(Color.YELLOW).bold()),
                         Span.raw(" scroll  "),
                         Span.styled("PgUp/PgDn", 
Style.create().fg(Color.YELLOW).bold()),
                         Span.raw(" page"));

Reply via email to