diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aa08809d1d7e0b013f95f40dde8dd9c737f966e..35ae72ed0efe58b061c40a334ccd3b818c6cada4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ current (development) --------------------- ### DOM +- Feature: more styles: + - `strikethrough` + - `underlinedDouble` - Feature: Customize the cursor. Add the following decorators: - `focusCursorBlock` - `focusCursorBlockBlinking` diff --git a/CMakeLists.txt b/CMakeLists.txt index dab2557c1e350cc805b8add0dc92cd9d2e290431..adb4ec58c91fc474e34ef1daa9bb0b1613e98254 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,9 +79,11 @@ add_library(dom src/ftxui/dom/separator.cpp src/ftxui/dom/size.cpp src/ftxui/dom/spinner.cpp + src/ftxui/dom/strikethrough.cpp src/ftxui/dom/table.cpp src/ftxui/dom/text.cpp src/ftxui/dom/underlined.cpp + src/ftxui/dom/underlined_double.cpp src/ftxui/dom/util.cpp src/ftxui/dom/vbox.cpp ) diff --git a/README.md b/README.md index c9aa65cb446126c11fb06a7c7a47eecbe4fdcda6..7f1b0670952fb0ac334d09a0f6361ddab2f9d9c0 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,9 @@ An element can be decorated using the functions: - `dim` - `inverted` - `underlined` + - `underlinedDouble` - `blink` + - `strikethrough` - `color` - `bgcolor` diff --git a/doc/mainpage.md b/doc/mainpage.md index 2395748f4a85ff76da18628b9e8c25acf535141d..9c03660206842b104df25c5eb272e2f84c962d55 100644 --- a/doc/mainpage.md +++ b/doc/mainpage.md @@ -453,6 +453,8 @@ Element bold(Element); Element dim(Element); Element inverted(Element); Element underlined(Element); +Element underlinedDouble(Element); +Element strikethrough(Element); Element blink(Element); Decorator color(Color); Decorator bgcolor(Color); @@ -469,7 +471,7 @@ underlined(bold(text("This text is bold and underlined"))) Alternatively, use the pipe operator to chain it on your element: ```cpp -text("This text is bold")) | bold | underlined +text("This text is bold") | bold | underlined ``` ## Layout {#dom-layout} diff --git a/examples/dom/CMakeLists.txt b/examples/dom/CMakeLists.txt index ee2265ce60d80b9ed39a0af502952b97b31f277d..df6e1b9cc4537fc23114b85cc854edf132e94b6e 100644 --- a/examples/dom/CMakeLists.txt +++ b/examples/dom/CMakeLists.txt @@ -26,7 +26,9 @@ example(style_color) example(style_dim) example(style_gallery) example(style_inverted) +example(style_strikethrough) example(style_underlined) +example(style_underlined_double) example(table) example(vbox_hbox) example(vflow) diff --git a/examples/dom/style_gallery.cpp b/examples/dom/style_gallery.cpp index 9303e67efa0f21cde4f1e58bd4d44323468ae84d..88263888e11eb8dc2e820c071a7f42d3a431682b 100644 --- a/examples/dom/style_gallery.cpp +++ b/examples/dom/style_gallery.cpp @@ -10,14 +10,16 @@ int main(int argc, const char* argv[]) { // clang-format off auto document = hbox({ - text("normal") , text(" ") , - text("bold") | bold , text(" ") , - text("dim") | dim , text(" ") , - text("inverted") | inverted , text(" ") , - text("underlined")| underlined , text(" ") , - text("blink") | blink , text(" ") , - text("color") | color(Color::Blue) , text(" ") , - text("bgcolor") | bgcolor(Color::Blue), + text("normal") , text(" ") , + text("bold") | bold , text(" ") , + text("dim") | dim , text(" ") , + text("inverted") | inverted , text(" ") , + text("underlined") | underlined , text(" ") , + text("underlinedDouble") | underlinedDouble , text(" ") , + text("blink") | blink , text(" ") , + text("strikethrough") | strikethrough , text(" ") , + text("color") | color(Color::Blue) , text(" ") , + text("bgcolor") | bgcolor(Color::Blue) , }); // clang-format on auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); diff --git a/examples/dom/style_strikethrough.cpp b/examples/dom/style_strikethrough.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2c8355f63da035f8ce4347f938a768ea572a283 --- /dev/null +++ b/examples/dom/style_strikethrough.cpp @@ -0,0 +1,25 @@ +#include <ftxui/dom/elements.hpp> // for text, operator|, strikethrough, Fit, hbox, Element +#include <ftxui/screen/screen.hpp> // for Full, Screen +#include <memory> // for allocator + +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/color.hpp" // for ftxui + +int main(int argc, const char* argv[]) { + using namespace ftxui; + auto document = // + hbox({ + text("This text is "), + text("strikethrough") | strikethrough, + text(". Do you like it?"), + }); + auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); + Render(screen, document); + screen.Print(); + + return 0; +} + +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/examples/dom/style_underlined_double.cpp b/examples/dom/style_underlined_double.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ea2a99840b5f239aa2f4de1e0848bf16632af0fe --- /dev/null +++ b/examples/dom/style_underlined_double.cpp @@ -0,0 +1,25 @@ +#include <ftxui/dom/elements.hpp> // for text, operator|, underlinedDouble, Fit, hbox, Element +#include <ftxui/screen/screen.hpp> // for Full, Screen +#include <memory> // for allocator + +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/color.hpp" // for ftxui + +int main(int argc, const char* argv[]) { + using namespace ftxui; + auto document = // + hbox({ + text("This text is "), + text("underlinedDouble") | underlinedDouble, + text(". Do you like it?"), + }); + auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); + Render(screen, document); + screen.Print(); + + return 0; +} + +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index ce14801691454b93f33f5118b541be791fe9662f..b3935c50983162666ec9b14c263fbc03c2fc1fa3 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -83,7 +83,9 @@ Element bold(Element); Element dim(Element); Element inverted(Element); Element underlined(Element); +Element underlinedDouble(Element); Element blink(Element); +Element strikethrough(Element); Decorator color(Color); Decorator bgcolor(Color); Element color(Color, Element); diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp index 96242a3635e1b7b9df877e9f19ba124b87206e9d..d8a5329db2747ce8e78404b633aec5b5b6f3eacc 100644 --- a/include/ftxui/screen/screen.hpp +++ b/include/ftxui/screen/screen.hpp @@ -30,6 +30,8 @@ struct Pixel { bool dim : 1; bool inverted : 1; bool underlined : 1; + bool underlined_double : 1; + bool strikethrough : 1; bool automerge : 1; Pixel() @@ -38,6 +40,8 @@ struct Pixel { dim(false), inverted(false), underlined(false), + underlined_double(false), + strikethrough(false), automerge(false) {} }; diff --git a/src/ftxui/dom/strikethrough.cpp b/src/ftxui/dom/strikethrough.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13c8559ea80051c1a36f8295d8d1c5a4f4a22469 --- /dev/null +++ b/src/ftxui/dom/strikethrough.cpp @@ -0,0 +1,36 @@ +#include <memory> // for make_shared +#include <utility> // for move + +#include "ftxui/dom/elements.hpp" // for Element, strikethrough +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/screen.hpp" // for Pixel, Screen + +namespace ftxui { + +/// @brief Apply a strikethrough to text. +/// @ingroup dom +Element strikethrough(Element child) { + class Impl : public NodeDecorator { + public: + using NodeDecorator::NodeDecorator; + + 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).strikethrough = true; + } + } + Node::Render(screen); + } + }; + + return std::make_shared<Impl>(std::move(child)); +} + +} // namespace ftxui + +// Copyright 2023 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/src/ftxui/dom/underlined_double.cpp b/src/ftxui/dom/underlined_double.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1089f7bb863c3becd4374780dc23601da94b2b1 --- /dev/null +++ b/src/ftxui/dom/underlined_double.cpp @@ -0,0 +1,36 @@ +#include <memory> // for make_shared +#include <utility> // for move + +#include "ftxui/dom/elements.hpp" // for Element, underlinedDouble +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/screen.hpp" // for Pixel, Screen + +namespace ftxui { + +/// @brief Apply a underlinedDouble to text. +/// @ingroup dom +Element underlinedDouble(Element child) { + class Impl : public NodeDecorator { + public: + using NodeDecorator::NodeDecorator; + + 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).underlined_double = true; + } + } + Node::Render(screen); + } + }; + + return std::make_shared<Impl>(std::move(child)); +} + +} // namespace ftxui + +// Copyright 2023 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index 96cef9f28e7e1603ae448d8331115e5badc1942b..21a93cab550020761ce024aa00fe040a424f5b5d 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -66,6 +66,16 @@ void UpdatePixelStyle(std::stringstream& ss, previous.dim = false; } + if ((!next.underlined && previous.underlined) || + (!next.underlined_double && previous.underlined_double)) { + // We might have wrongfully reset underlined or underlinedbold because they + // share the same resetter. Take it into account so that the side effect + // will cause it to be set again below. + ss << "\x1B[24m"; // UNDERLINED_RESET + previous.underlined = false; + previous.underlined_double = false; + } + if (next.bold && !previous.bold) { ss << "\x1B[1m"; // BOLD_SET } @@ -78,10 +88,6 @@ void UpdatePixelStyle(std::stringstream& ss, ss << "\x1B[4m"; // UNDERLINED_SET } - if (!next.underlined && previous.underlined) { - ss << "\x1B[24m"; // UNDERLINED_RESET - } - if (next.blink && !previous.blink) { ss << "\x1B[5m"; // BLINK_SET } @@ -98,6 +104,18 @@ void UpdatePixelStyle(std::stringstream& ss, ss << "\x1B[27m"; // INVERTED_RESET } + if (next.strikethrough && !previous.strikethrough) { + ss << "\x1B[9m"; // CROSSED_OUT + } + + if (!next.strikethrough && previous.strikethrough) { + ss << "\x1B[29m"; // CROSSED_OUT_RESET + } + + if (next.underlined_double && !previous.underlined_double) { + ss << "\x1B[21m"; // DOUBLE_UNDERLINED_SET + } + if (next.foreground_color != previous.foreground_color || next.background_color != previous.background_color) { ss << "\x1B[" + next.foreground_color.Print(false) + "m";