Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add colored border. #595

Merged
merged 1 commit into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ current (development)

### Dom
- Feature: Add the dashed style for border and separator.
- Feature: Add colored borders.

###
- Breaking: Direction enum is renamed WidthOrHeight
Expand Down
1 change: 1 addition & 0 deletions examples/dom/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
set(DIRECTORY_LIB dom)

example(border)
example(border_colored)
example(border_style)
example(color_gallery)
example(color_info_palette256)
Expand Down
40 changes: 40 additions & 0 deletions examples/dom/border_colored.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <ftxui/dom/elements.hpp> // for operator|, text, Element, Fit, borderDouble, borderHeavy, borderLight, borderRounded, vbox
#include <ftxui/screen/screen.hpp> // for Screen
#include <iostream> // for endl, cout, ostream
#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 make_boxed = [] {
return vbox({
text("borderLight") | borderStyled(LIGHT, Color::Red),
text("borderDashed") | borderStyled(DASHED, Color::Green),
text("borderHeavy") | borderStyled(HEAVY, Color::Blue),
text("borderDouble") | borderStyled(DOUBLE, Color::Yellow),
text("borderRounded") | borderStyled(ROUNDED, Color::Cyan),
});
};

auto document = hbox({
make_boxed(),
separator() | color(Color::Red),
make_boxed(),
separator() | color(Color::Red),
make_boxed(),
}) |
borderStyled(ROUNDED, Color::Red);

auto screen =
Screen::Create(Dimension::Fit(document), Dimension::Fit(document));
Render(screen, document);
screen.Print();
std::cout << std::endl;
}

// 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.
2 changes: 2 additions & 0 deletions include/ftxui/dom/elements.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ Element borderDouble(Element);
Element borderRounded(Element);
Element borderEmpty(Element);
Decorator borderStyled(BorderStyle);
Decorator borderStyled(BorderStyle, Color);
Decorator borderStyled(Color);
Decorator borderWith(const Pixel&);
Element window(Element title, Element content);
Element spinner(int charset_index, size_t image_index);
Expand Down
61 changes: 50 additions & 11 deletions src/ftxui/dom/border.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include <algorithm> // for max
#include <array> // for array
#include <memory> // for allocator, make_shared, __shared_ptr_access
#include <string> // for basic_string, string
#include <utility> // for move
#include <vector> // for __alloc_traits<>::value_type
#include <optional>
#include <string> // for basic_string, string
#include <utility> // for move
#include <vector> // for __alloc_traits<>::value_type

#include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, BorderStyle, ROUNDED, Elements, DOUBLE, EMPTY, HEAVY, LIGHT, border, borderDouble, borderEmpty, borderHeavy, borderLight, borderRounded, borderStyled, borderWith, window
#include "ftxui/dom/node.hpp" // for Node, Elements
Expand All @@ -17,22 +18,26 @@ using Charset = std::array<std::string, 6>; // NOLINT
using Charsets = std::array<Charset, 6>; // NOLINT
// NOLINTNEXTLINE
static Charsets simple_border_charset = {
Charset{"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
Charset{"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
Charset{"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
Charset{"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
Charset{"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
Charset{" ", " ", " ", " ", " ", " "}, // EMPTY
Charset{"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
Charset{"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
Charset{"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
Charset{"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
Charset{"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
Charset{" ", " ", " ", " ", " ", " "}, // EMPTY
};

// For reference, here is the charset for normal border:
class Border : public Node {
public:
Border(Elements children, BorderStyle style)
Border(Elements children,
BorderStyle style,
std::optional<Color> foreground_color = std::nullopt)
: Node(std::move(children)),
charset_(simple_border_charset[style]) {} // NOLINT
charset_(simple_border_charset[style]),
foreground_color_(foreground_color) {} // NOLINT

const Charset& charset_; // NOLINT
std::optional<Color> foreground_color_;

void ComputeRequirement() override {
Node::ComputeRequirement();
Expand Down Expand Up @@ -101,6 +106,18 @@ class Border : public Node {
if (children_.size() == 2) {
children_[1]->Render(screen);
}

// Draw the border color.
if (foreground_color_) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x, box_.y_min).foreground_color = *foreground_color_;
screen.PixelAt(x, box_.y_max).foreground_color = *foreground_color_;
}
for (int y = box_.y_min; y <= box_.y_max; ++y) {
screen.PixelAt(box_.x_min, y).foreground_color = *foreground_color_;
screen.PixelAt(box_.x_max, y).foreground_color = *foreground_color_;
}
}
}
};

Expand Down Expand Up @@ -179,6 +196,8 @@ class BorderPixel : public Node {
/// @see borderHeavy
/// @see borderEmpty
/// @see borderRounded
/// @see borderStyled
/// @see borderWith
///
/// Add a border around an element
///
Expand Down Expand Up @@ -221,6 +240,26 @@ Decorator borderStyled(BorderStyle style) {
};
}

/// @brief Same as border but with a foreground color.
/// @ingroup dom
/// @see border
Decorator borderStyled(Color foreground_color) {
return [foreground_color](Element child) {
return std::make_shared<Border>(unpack(std::move(child)), ROUNDED,
foreground_color);
};
}

/// @brief Same as border but with a foreground color and a different style
/// @ingroup dom
/// @see border
Decorator borderStyled(BorderStyle style, Color foreground_color) {
return [style, foreground_color](Element child) {
return std::make_shared<Border>(unpack(std::move(child)), style,
foreground_color);
};
}

/// @brief Draw a light border around the element.
/// @ingroup dom
/// @see border
Expand Down