54uint8_t g_map_braille[2][4][2] = {
56 {0b00000000, 0b00000001},
57 {0b00000000, 0b00000010},
58 {0b00000000, 0b00000100},
59 {0b00000001, 0b00000000},
62 {0b00000000, 0b00001000},
63 {0b00000000, 0b00010000},
64 {0b00000000, 0b00100000},
65 {0b00000010, 0b00000000},
70std::vector<std::string> g_map_block = {
71 " ",
"▘",
"▖",
"▌",
"▝",
"▀",
"▞",
"▛",
72 "▗",
"▚",
"▄",
"▙",
"▐",
"▜",
"▟",
"█",
76const std::map<std::string, uint8_t> g_map_block_inversed = {
77 {
" ", 0b0000}, {
"▘", 0b0001}, {
"▖", 0b0010}, {
"▌", 0b0011},
78 {
"▝", 0b0100}, {
"▀", 0b0101}, {
"▞", 0b0110}, {
"▛", 0b0111},
79 {
"▗", 0b1000}, {
"▚", 0b1001}, {
"▄", 0b1010}, {
"▙", 0b1011},
80 {
"▐", 0b1100}, {
"▜", 0b1101}, {
"▟", 0b1110}, {
"█", 0b1111},
83constexpr auto nostyle = [](Pixel& ) {};
93 storage_(width_ * height_ / 8 ) {}
99 auto it = storage_.find(XY{x, y});
100 return (it == storage_.end()) ?
Pixel() : it->second.content;
141 Cell& cell = storage_[XY{x / 2, y / 4}];
142 if (cell.type != CellType::kBraille) {
144 cell.type = CellType::kBraille;
147 cell.content.
character[1] |= g_map_braille[x % 2][y % 4][0];
148 cell.content.
character[2] |= g_map_braille[x % 2][y % 4][1];
158 Cell& cell = storage_[XY{x / 2, y / 4}];
159 if (cell.type != CellType::kBraille) {
161 cell.type = CellType::kBraille;
164 cell.content.
character[1] &= ~(g_map_braille[x % 2][y % 4][0]);
165 cell.content.
character[2] &= ~(g_map_braille[x % 2][y % 4][1]);
176 Cell& cell = storage_[XY{x / 2, y / 4}];
177 if (cell.type != CellType::kBraille) {
179 cell.type = CellType::kBraille;
182 cell.content.
character[1] ^= g_map_braille[x % 2][y % 4][0];
183 cell.content.
character[2] ^= g_map_braille[x % 2][y % 4][1];
217 const int dx = std::abs(x2 - x1);
218 const int dy = std::abs(y2 - y1);
219 const int sx = x1 < x2 ? 1 : -1;
220 const int sy = y1 < y2 ? 1 : -1;
221 const int length = std::max(dx, dy);
223 if (!IsIn(x1, y1) && !IsIn(x2, y2)) {
226 if (dx + dx > width_ * height_) {
231 for (
int i = 0; i < length; ++i) {
233 if (2 * error >= -dy) {
237 if (2 * error <= dx) {
288 const Color& color) {
324 const Color& color) {
343 int dx = (1 + 2 * x) * e2 * e2;
355 err += dx += 2 * r2 * r2;
359 err += dy += 2 * r1 * r1;
388 const Color& color) {
407 int dx = (1 + 2 * x) * e2 * e2;
412 for (
int xx = x1 + x; xx <= x1 - x; ++xx) {
419 err += dx += 2 * r2 * r2;
423 err += dy += 2 * r1 * r1;
428 for (
int yy = y1 - y; yy <= y1 + y; ++yy) {
473 Cell& cell = storage_[XY{x / 2, y / 2}];
474 if (cell.type != CellType::kBlock) {
476 cell.type = CellType::kBlock;
479 const uint8_t bit = (x % 2) * 2 + y % 2;
480 uint8_t value = g_map_block_inversed.at(cell.content.
character);
482 cell.content.
character = g_map_block[value];
492 Cell& cell = storage_[XY{x / 2, y / 4}];
493 if (cell.type != CellType::kBlock) {
495 cell.type = CellType::kBlock;
499 const uint8_t bit = (y % 2) * 2 + x % 2;
500 uint8_t value = g_map_block_inversed.at(cell.content.
character);
501 value &= ~(1U << bit);
502 cell.content.
character = g_map_block[value];
513 Cell& cell = storage_[XY{x / 2, y / 4}];
514 if (cell.type != CellType::kBlock) {
516 cell.type = CellType::kBlock;
520 const uint8_t bit = (y % 2) * 2 + x % 2;
521 uint8_t value = g_map_block_inversed.at(cell.content.
character);
523 cell.content.
character = g_map_block[value];
560 const int dx = std::abs(x2 - x1);
561 const int dy = std::abs(y2 - y1);
562 const int sx = x1 < x2 ? 1 : -1;
563 const int sy = y1 < y2 ? 1 : -1;
564 const int length = std::max(dx, dy);
566 if (!IsIn(x1, y1) && !IsIn(x2, y2)) {
569 if (dx + dx > width_ * height_) {
574 for (
int i = 0; i < length; ++i) {
576 if (2 * error >= -dy) {
580 if (2 * error <= dx) {
631 const Color& color) {
667 const Color& color) {
688 int dx = (1 + 2 * x) * e2 * e2;
693 DrawBlock(x1 - x, 2 * (y1 + y),
true, s);
694 DrawBlock(x1 + x, 2 * (y1 + y),
true, s);
695 DrawBlock(x1 + x, 2 * (y1 - y),
true, s);
696 DrawBlock(x1 - x, 2 * (y1 - y),
true, s);
700 err += dx += 2 * r2 * r2;
704 err += dy += 2 * r1 * r1;
733 const Color& color) {
754 int dx = (1 + 2 * x) * e2 * e2;
759 for (
int xx = x1 + x; xx <= x1 - x; ++xx) {
766 err += dx += 2 * r2 * r2;
770 err += dy += 2 * r1 * r1;
775 for (
int yy = y1 + y; yy <= y1 - y; ++yy) {
796 const std::string& value,
797 const Color& color) {
808 const std::string& value,
815 Cell& cell = storage_[XY{x / 2, y / 4}];
816 cell.type = CellType::kCell;
828 Cell& cell = storage_[XY{x / 2, y / 4}];
829 cell.type = CellType::kCell;
842 const int dx_begin = std::max(0, -x);
843 const int dy_begin = std::max(0, -y);
844 const int dx_end = std::min(image.
dimx(), width_ - x);
845 const int dy_end = std::min(image.
dimy(), height_ - y);
847 for (
int dy = dy_begin; dy < dy_end; ++dy) {
848 for (
int dx = dx_begin; dx < dx_end; ++dx) {
849 Cell& cell = storage_[XY{
853 cell.type = CellType::kCell;
854 cell.content = image.
PixelAt(dx, dy);
863 style(storage_[XY{x / 2, y / 4}].content);
869class CanvasNodeBase :
public Node {
871 CanvasNodeBase() =
default;
875 const int y_max = std::min(c.
height() / 4, box_.y_max - box_.y_min + 1);
876 const int x_max = std::min(c.
width() / 2, box_.x_max - box_.x_min + 1);
877 for (
int y = 0; y < y_max; ++y) {
878 for (
int x = 0; x < x_max; ++x) {
879 screen.PixelAt(box_.x_min + x, box_.y_min + y) = c.
GetPixel(x, y);
884 virtual const Canvas&
canvas() = 0;
892 class Impl :
public CanvasNodeBase {
895 requirement_.min_x = (canvas_->width() + 1) / 2;
896 requirement_.min_y = (canvas_->height() + 3) / 4;
898 const Canvas& canvas()
final {
return *canvas_; }
901 return std::make_shared<Impl>(canvas);
909 class Impl :
public CanvasNodeBase {
911 Impl(
int width,
int height, std::function<
void(
Canvas&)> fn)
912 : width_(width), height_(height), fn_(std::move(fn)) {}
914 void ComputeRequirement()
final {
915 requirement_.min_x = (width_ + 1) / 2;
916 requirement_.min_y = (height_ + 3) / 4;
920 const int width = (box_.x_max - box_.x_min + 1) * 2;
921 const int height = (box_.y_max - box_.y_min + 1) * 4;
922 canvas_ =
Canvas(width, height);
924 CanvasNodeBase::Render(
screen);
927 const Canvas& canvas()
final {
return canvas_; }
931 std::function<void(
Canvas&)> fn_;
933 return std::make_shared<Impl>(width, height, std::move(fn));
939 const int default_dim = 12;
940 return canvas(default_dim, default_dim, std::move(fn));
Un adaptateur. Possède ou référence un objet immuable.
void DrawImage(int x, int y, const Image &)
Dessine une image prédéfinie, avec le coin supérieur gauche à la coordonnée donnée Vous pouvez fourni...
void DrawBlockLine(int x1, int y1, int x2, int y2)
Dessine une ligne de caractères de bloc.
void DrawPointEllipseFilled(int x, int y, int r1, int r2)
Dessine une ellipse remplie de points braille.
void DrawPointLine(int x1, int y1, int x2, int y2)
Dessine une ligne de points braille.
void DrawText(int x, int y, const std::string &value)
Dessine un morceau de texte.
std::function< void(Pixel &)> Stylizer
void DrawBlockOn(int x, int y)
Dessine un bloc.
void DrawPointCircleFilled(int x, int y, int radius)
Dessine un cercle rempli de points braille.
void DrawPointOn(int x, int y)
Dessine un point braille.
void DrawPointOff(int x, int y)
Efface un point braille.
Pixel GetPixel(int x, int y) const
Récupère le contenu d'une cellule.
void DrawBlockEllipseFilled(int x1, int y1, int r1, int r2)
Dessine une ellipse remplie de caractères de bloc.
void DrawPointEllipse(int x, int y, int r1, int r2)
Dessine une ellipse de points braille.
void DrawPoint(int x, int y, bool value)
Dessine un point braille.
void DrawBlockEllipse(int x1, int y1, int r1, int r2)
Dessine une ellipse de caractères de bloc.
void DrawBlockToggle(int x, int y)
Inverse un bloc. S'il est rempli, il sera effacé. S'il est vide, il sera rempli.
void DrawBlockCircle(int x1, int y1, int radius)
Dessine un cercle de caractères de bloc.
void DrawBlockCircleFilled(int x1, int y1, int radius)
Dessine un cercle rempli de caractères de bloc.
void DrawPointCircle(int x, int y, int radius)
Dessine un cercle de points braille.
void DrawBlockOff(int x, int y)
Efface un bloc.
void DrawBlock(int x, int y, bool value)
Dessine un bloc.
void Style(int x, int y, const Stylizer &style)
Modifie un pixel à un emplacement donné.
void DrawPointToggle(int x, int y)
Inverse un point braille. Un point rempli sera effacé, et un point vide sera dessiné.
void DrawPixel(int x, int y, const Pixel &)
Dessine directement un pixel prédéfini à la coordonnée donnée.
Node est la classe de base pour tous les éléments de l'arbre DOM.
void Render(Screen &screen, const Element &element)
Affiche un élément sur un ftxui::Screen.
Decorator color(Color)
Décore en utilisant une couleur de premier plan.
Canvas est un tampon dessinable associé aux opérations de dessin.
Pixel & PixelAt(int x, int y)
Accède à une cellule (Pixel) à une position donnée.
Color est une classe qui représente une couleur dans l'interface utilisateur du terminal.
Une grille rectangulaire de pixels.
Une grille rectangulaire de pixels.
Un caractère Unicode et son style associé.
L'espace de noms FTXUI ftxui::
std::shared_ptr< Node > Element
std::vector< std::string > Utf8ToGlyphs(const std::string &input)
Element canvas(ConstRef< Canvas >)
Produit un élément à partir d'un Canevas, ou une référence à un Canevas.
void Render(Screen &screen, const Element &element)