diff --git a/CHANGELOG.md b/CHANGELOG.md index 55a255e390b714b25b6bb2ba4b3c1751c52ea8c7..c4a7983e5760a3185cfab8dd7678ddb6bbc784b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ current (development) ### DOM - Bugfix: Fix `focus`/`select` when the `vbox`/`hbox`/`dbox` contains a `flexbox` +- Bugfix: Fix the selected/focused area. It used to be 1 cell larger/longer than + requested +- Bugfix: Forward the selected/focused area from the child in gridbox. ### Screen - Feature: add `Box::Union(a,b) -> Box` diff --git a/src/ftxui/dom/flexbox_test.cpp b/src/ftxui/dom/flexbox_test.cpp index b5175f6d483b4c392eea51d3a2383c65e449273f..dca5913942c4fa107b3e4e8f393502ab493e8a09 100644 --- a/src/ftxui/dom/flexbox_test.cpp +++ b/src/ftxui/dom/flexbox_test.cpp @@ -449,9 +449,9 @@ TEST(FlexboxTest, Focus) { Screen screen(1, 3); Render(screen, document); EXPECT_EQ(screen.ToString(), - "7\r\n" "-\r\n" - "8" + "7\r\n" + "-" ); } diff --git a/src/ftxui/dom/frame.cpp b/src/ftxui/dom/frame.cpp index b67c7bb542c99e3f14bfe34cffa95b5a0b8e3dd7..575bbc84cedd57d7e5cf9aa835bac5f213d1931c 100644 --- a/src/ftxui/dom/frame.cpp +++ b/src/ftxui/dom/frame.cpp @@ -24,8 +24,8 @@ class Select : public Node { auto& selected_box = requirement_.selected_box; selected_box.x_min = 0; selected_box.y_min = 0; - selected_box.x_max = requirement_.min_x; - selected_box.y_max = requirement_.min_y; + selected_box.x_max = requirement_.min_x - 1; + selected_box.y_max = requirement_.min_y - 1; requirement_.selection = Requirement::SELECTED; }; diff --git a/src/ftxui/dom/gridbox.cpp b/src/ftxui/dom/gridbox.cpp index 9bc21974faf40a23749f6ae0ccf3009ab079e4f3..abc12d28a30b5e546dcad571692e285ce97c9add 100644 --- a/src/ftxui/dom/gridbox.cpp +++ b/src/ftxui/dom/gridbox.cpp @@ -13,6 +13,23 @@ namespace ftxui { class Screen; +namespace { + +// Accumulate the values of a list U[n] into v[n]. So that: +// V[0] = 0; +// V[n+1] = v[n] + U[n] +// return the sum of U[n]. +int Integrate(std::vector<int>& elements) { + int accu = 0; + for (auto& i : elements) { + int old_accu = accu; + accu += i; + i = old_accu; + } + return accu; +} +} + class GridBox : public Node { public: explicit GridBox(std::vector<Elements> lines) : lines_(std::move(lines)) { @@ -38,34 +55,36 @@ class GridBox : public Node { for (auto& line : lines_) { for (auto& cell : line) { cell->ComputeRequirement(); - - // Determine focus based on the focused child. - if (requirement_.selection >= cell->requirement().selection) { - continue; - } - requirement_.selection = cell->requirement().selection; - requirement_.selected_box = cell->requirement().selected_box; - requirement_.selected_box.x_min += requirement_.min_x; - requirement_.selected_box.x_max += requirement_.min_x; } } - // Work on the x-axis. + // Compute the size of each columns/row. + std::vector<int> size_x(x_size, 0); + std::vector<int> size_y(y_size, 0); for (int x = 0; x < x_size; ++x) { - int min_x = 0; for (int y = 0; y < y_size; ++y) { - min_x = std::max(min_x, lines_[y][x]->requirement().min_x); + size_x[x] = std::max(size_x[x], lines_[y][x]->requirement().min_x); + size_y[y] = std::max(size_y[y], lines_[y][x]->requirement().min_y); } - requirement_.min_x += min_x; } - // Work on the y-axis. - for (int y = 0; y < y_size; ++y) { - int min_y = 0; - for (int x = 0; x < x_size; ++x) { - min_y = std::max(min_y, lines_[y][x]->requirement().min_y); + requirement_.min_x = Integrate(size_x); + requirement_.min_y = Integrate(size_y); + + // Forward the selected/focused child state: + requirement_.selection = Requirement::NORMAL; + for (int x = 0; x < x_size; ++x) { + for (int y = 0; y < y_size; ++y) { + if (requirement_.selection >= lines_[y][x]->requirement().selection) { + continue; + } + requirement_.selection = lines_[y][x]->requirement().selection; + requirement_.selected_box = lines_[y][x]->requirement().selected_box; + requirement_.selected_box.x_min += size_x[x]; + requirement_.selected_box.x_max += size_x[x]; + requirement_.selected_box.y_min += size_y[y]; + requirement_.selected_box.y_max += size_y[y]; } - requirement_.min_y += min_y; } } diff --git a/src/ftxui/dom/gridbox_test.cpp b/src/ftxui/dom/gridbox_test.cpp index 19a8f8b162d284ffca86b337ffff1b916fa91eca..f358d4fca96abf66ed5001e3cc0c7b1e886bf015 100644 --- a/src/ftxui/dom/gridbox_test.cpp +++ b/src/ftxui/dom/gridbox_test.cpp @@ -596,6 +596,25 @@ TEST(GridboxTest, MissingCells) { " "); } +TEST(GridboxTest, Focus) { + auto root = gridbox({ + {cell("1"), cell("2"), cell("3"), cell("4")}, + {cell("5"), cell("6"), cell("7"), cell("8")}, + {cell("9"), cell("10"), cell("11"), cell("12")}, + {cell("13"), cell("14") | focus, cell("15"), cell("16")}, + {cell("17"), cell("18"), cell("19"), cell("20")}, + }); + + root |= frame; + + Screen screen(4, 3); + Render(screen, root); + EXPECT_EQ(screen.ToString(), + "╭──╮\r\n" + "│14│\r\n" + "╰──╯"); +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved.