From 6039474a2606bdfb2f041b6f53f5e9ababc68777 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Sat, 22 Jan 2022 15:38:01 +0100 Subject: [PATCH] Automerge feature. (#313) Add the `automerge` attribute to the Pixel bit field. It controls whether two pixels must be automerged. Defining this allows two mergeable characters not to be merged. This was requested by: https://github.com/ArthurSonzogni/FTXUI/issues/285 --- CHANGELOG.md | 7 +++++++ include/ftxui/screen/screen.hpp | 4 +++- src/ftxui/dom/border.cpp | 33 +++++++++++++++++++++++++-------- src/ftxui/dom/separator.cpp | 12 +++++++++--- src/ftxui/screen/screen.cpp | 22 ++++++++++++---------- 5 files changed, 56 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e14fe2..c3b8df5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ unreleased (development) ### Features: +#### Screen +- Add the `automerge` to the Pixel bit field. This now controls which pixels are + automatically merged. + #### DOM: - Add the `Canvas` class and `ElementFrom('canvas')` function. Together users of the library can draw using braille and block characters. @@ -30,6 +34,9 @@ unreleased (development) ### Bug +#### Table +- The `table` horizontal and vertical separator are now correctly expanded. + #### Component - `Input` shouldn't take focus when hovered by the mouse. - Modifying `Input`'s during on_enter/on_change event is now working correctly. diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp index 9e609b6..45d8c14 100644 --- a/include/ftxui/screen/screen.hpp +++ b/include/ftxui/screen/screen.hpp @@ -28,13 +28,15 @@ struct Pixel { bool dim : 1; bool inverted : 1; bool underlined : 1; + bool automerge : 1; Pixel() : blink(false), bold(false), dim(false), inverted(false), - underlined(false) {} + underlined(false), + automerge(false) {} }; /// @brief Define how the Screen's dimensions should look like. diff --git a/src/ftxui/dom/border.cpp b/src/ftxui/dom/border.cpp index 0b7d7a9..236c3b8 100644 --- a/src/ftxui/dom/border.cpp +++ b/src/ftxui/dom/border.cpp @@ -89,13 +89,22 @@ class Border : public Node { screen.at(box_.x_max, box_.y_min) = charset[1]; screen.at(box_.x_min, box_.y_max) = charset[2]; screen.at(box_.x_max, box_.y_max) = charset[3]; + for (float x = box_.x_min + 1; x < box_.x_max; ++x) { - screen.at(x, box_.y_min) = charset[4]; - screen.at(x, box_.y_max) = charset[4]; + Pixel& p1 = screen.PixelAt(x, box_.y_min); + Pixel& p2 = screen.PixelAt(x, box_.y_max); + p1.character = charset[4]; + p2.character = charset[4]; + p1.automerge = true; + p2.automerge = true; } for (float y = box_.y_min + 1; y < box_.y_max; ++y) { - screen.at(box_.x_min, y) = charset[5]; - screen.at(box_.x_max, y) = charset[5]; + Pixel& p3 = screen.PixelAt(box_.x_min, y); + Pixel& p4 = screen.PixelAt(box_.x_max, y); + p3.character = charset[5]; + p4.character = charset[5]; + p3.automerge = true; + p4.automerge = true; } // Draw title. @@ -109,12 +118,20 @@ class Border : public Node { screen.PixelAt(box_.x_min, box_.y_max) = charset_pixel[2]; screen.PixelAt(box_.x_max, box_.y_max) = charset_pixel[3]; for (float x = box_.x_min + 1; x < box_.x_max; ++x) { - screen.PixelAt(x, box_.y_min) = charset_pixel[4]; - screen.PixelAt(x, box_.y_max) = charset_pixel[4]; + Pixel& p1 = screen.PixelAt(x, box_.y_min); + Pixel& p2 = screen.PixelAt(x, box_.y_max); + p1 = charset_pixel[5]; + p2 = charset_pixel[5]; + p1.automerge = true; + p2.automerge = true; } for (float y = box_.y_min + 1; y < box_.y_max; ++y) { - screen.PixelAt(box_.x_min, y) = charset_pixel[5]; - screen.PixelAt(box_.x_max, y) = charset_pixel[5]; + Pixel& p3 = screen.PixelAt(box_.x_min, y); + Pixel& p4 = screen.PixelAt(box_.x_max, y); + p3 = charset_pixel[5]; + p4 = charset_pixel[5]; + p3.automerge = true; + p4.automerge = true; } } }; diff --git a/src/ftxui/dom/separator.cpp b/src/ftxui/dom/separator.cpp index 74b4511..6ac0dd7 100644 --- a/src/ftxui/dom/separator.cpp +++ b/src/ftxui/dom/separator.cpp @@ -31,7 +31,9 @@ class Separator : public Node { void Render(Screen& screen) override { for (int y = box_.y_min; y <= box_.y_max; ++y) { for (int x = box_.x_min; x <= box_.x_max; ++x) { - screen.PixelAt(x, y).character = value_; + Pixel& pixel = screen.PixelAt(x, y); + pixel.character = value_; + pixel.automerge = true; } } } @@ -56,7 +58,9 @@ class SeparatorAuto : public Node { for (int y = box_.y_min; y <= box_.y_max; ++y) { for (int x = box_.x_min; x <= box_.x_max; ++x) { - screen.PixelAt(x, y).character = c; + Pixel& pixel = screen.PixelAt(x, y); + pixel.character = c; + pixel.automerge = true; } } } @@ -66,7 +70,9 @@ class SeparatorAuto : public Node { class SeparatorWithPixel : public SeparatorAuto { public: - SeparatorWithPixel(Pixel pixel) : SeparatorAuto(LIGHT), pixel_(pixel) {} + SeparatorWithPixel(Pixel pixel) : SeparatorAuto(LIGHT), pixel_(pixel) { + pixel_.automerge = true; + } void Render(Screen& screen) override { for (int y = box_.y_min; y <= box_.y_max; ++y) { for (int x = box_.x_min; x <= box_.x_max; ++x) { diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index ae2d9d0..014589e 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -317,6 +317,10 @@ void UpgradeTopDown(std::string& top, std::string& down) { } } +bool ShouldAttemptAutoMerge(Pixel& pixel) { + return pixel.automerge && pixel.character.size() == 3; +} + } // namespace /// A fixed dimension. @@ -457,19 +461,17 @@ void Screen::ApplyShader() { for (int y = 1; y < dimy_; ++y) { for (int x = 1; x < dimx_; ++x) { // Box drawing character uses exactly 3 byte. - std::string& cur = pixels_[y][x].character; - if (cur.size() != 3u) + Pixel& cur = pixels_[y][x]; + if (!ShouldAttemptAutoMerge(cur)) continue; - // Left vs current. - std::string& left = pixels_[y][x-1].character; - if (left.size() == 3u) - UpgradeLeftRight(left, cur); + Pixel& left = pixels_[y][x-1]; + Pixel& top = pixels_[y-1][x]; - // Top vs current. - std::string& top = pixels_[y-1][x].character; - if (top.size() == 3u) - UpgradeTopDown(top, cur); + if (ShouldAttemptAutoMerge(left)) + UpgradeLeftRight(left.character, cur.character); + if (ShouldAttemptAutoMerge(top)) + UpgradeTopDown(top.character, cur.character); } } }