From 70bc44d28b36bc7b7332a88e19e9ad99c270074b Mon Sep 17 00:00:00 2001
From: Boris Jaulmes <35749044+LordWhiro@users.noreply.github.com>
Date: Thu, 7 Nov 2024 21:07:09 +0100
Subject: [PATCH] Allow a Dimension::Fit to extend beyond the terminal maximum
 height (#950)

For long tables (and other DOM elements), one may want the screen to render on dimensions higher than the terminal.
Hence, this PR proposes a way to do so, with an optional parameter in the `Dimension::Fit` util function.

Discussions / Issues :
- https://github.com/ArthurSonzogni/FTXUI/issues/572
- https://github.com/ArthurSonzogni/FTXUI/discussions/949

Bug:https://github.com/ArthurSonzogni/FTXUI/issues/572
Fixed:Bug:https://github.com/ArthurSonzogni/FTXUI/issues/572
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
---
 CHANGELOG.md                   |  3 +++
 examples/dom/table.cpp         |  3 ++-
 include/ftxui/dom/elements.hpp |  2 +-
 src/ftxui/dom/util.cpp         | 17 ++++++++++++-----
 4 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 476b6336..bfbcfb15 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -46,6 +46,9 @@ current (development)
 - Feature: Add `hscroll_indicator`. It display an horizontal indicator
   reflecting the current scroll position. Proposed by @ibrahimnasson in
   [issue 752](https://github.com/ArthurSonzogni/FTXUI/issues/752)
+- Feature: Add `extend_beyond_screen` option to `Dimension::Fit(..)`, allowing
+  the element to be larger than the screen. Proposed by @LordWhiro. See #572 and
+  #949.
 
 ### Screen
 - Feature: Add `Box::IsEmpty()`.
diff --git a/examples/dom/table.cpp b/examples/dom/table.cpp
index 020a2afe..690dae4c 100644
--- a/examples/dom/table.cpp
+++ b/examples/dom/table.cpp
@@ -55,7 +55,8 @@ int main() {
   content.DecorateCellsAlternateRow(color(Color::White), 3, 2);
 
   auto document = table.Render();
-  auto screen = Screen::Create(Dimension::Fit(document));
+  auto screen =
+      Screen::Create(Dimension::Fit(document, /*extend_beyond_screen=*/true));
   Render(screen, document);
   screen.Print();
   std::cout << std::endl;
diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp
index b17a7113..a2dd0442 100644
--- a/include/ftxui/dom/elements.hpp
+++ b/include/ftxui/dom/elements.hpp
@@ -183,7 +183,7 @@ Element align_right(Element);
 Element nothing(Element element);
 
 namespace Dimension {
-Dimensions Fit(Element&);
+Dimensions Fit(Element&, bool extend_beyond_screen = false);
 }  // namespace Dimension
 
 }  // namespace ftxui
diff --git a/src/ftxui/dom/util.cpp b/src/ftxui/dom/util.cpp
index 8fc4a9de..9bf2086e 100644
--- a/src/ftxui/dom/util.cpp
+++ b/src/ftxui/dom/util.cpp
@@ -90,7 +90,7 @@ Element& operator|=(Element& e, Decorator d) {
 /// The minimal dimension that will fit the given element.
 /// @see Fixed
 /// @see Full
-Dimensions Dimension::Fit(Element& e) {
+Dimensions Dimension::Fit(Element& e, bool extend_beyond_screen) {
   const Dimensions fullsize = Dimension::Full();
   Box box;
   box.x_min = 0;
@@ -106,7 +106,10 @@ Dimensions Dimension::Fit(Element& e) {
 
     // Don't give the element more space than it needs:
     box.x_max = std::min(box.x_max, e->requirement().min_x);
-    box.y_max = std::min(box.y_max, e->requirement().min_y);
+    box.y_max = e->requirement().min_y;
+    if (!extend_beyond_screen) {
+      box.y_max = std::min(box.y_max, fullsize.dimy);
+    }
 
     e->SetBox(box);
     status.need_iteration = false;
@@ -116,10 +119,14 @@ Dimensions Dimension::Fit(Element& e) {
     if (!status.need_iteration) {
       break;
     }
-    // Increase the size of the box until it fits, but not more than the with of
-    // the terminal emulator:
+    // Increase the size of the box until it fits...
     box.x_max = std::min(e->requirement().min_x, fullsize.dimx);
-    box.y_max = std::min(e->requirement().min_y, fullsize.dimy);
+    box.y_max = e->requirement().min_y;
+
+    // ... but don't go beyond the screen size:
+    if (!extend_beyond_screen) {
+      box.y_max = std::min(box.y_max, fullsize.dimy);
+    }
   }
 
   return {
-- 
GitLab