mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-04 13:38:14 +08:00 
			
		
		
		
	Fix: Forward gridbox selected box. (#408)
				
					
				
			This was discovered in: https://github.com/ArthurSonzogni/FTXUI/issues/407
This commit is contained in:
		@@ -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`
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
            "-"
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,35 +55,37 @@ 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) {
 | 
			
		||||
    // 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) {
 | 
			
		||||
      for (int y = 0; y < y_size; ++y) {
 | 
			
		||||
        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 = 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 = 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;
 | 
			
		||||
        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];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Work on the x-axis.
 | 
			
		||||
    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);
 | 
			
		||||
      }
 | 
			
		||||
      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_y += min_y;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void SetBox(Box box) override {
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user