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]);
175 Cell& cell = storage_[XY{x / 2, y / 4}];
176 if (cell.type != CellType::kBraille) {
178 cell.type = CellType::kBraille;
181 cell.content.
character[1] ^= g_map_braille[x % 2][y % 4][0];
182 cell.content.
character[2] ^= g_map_braille[x % 2][y % 4][1];
216 const int dx = std::abs(x2 - x1);
217 const int dy = std::abs(y2 - y1);
218 const int sx = x1 < x2 ? 1 : -1;
219 const int sy = y1 < y2 ? 1 : -1;
220 const int length = std::max(dx, dy);
222 if (!IsIn(x1, y1) && !IsIn(x2, y2)) {
225 if (dx + dx > width_ * height_) {
230 for (
int i = 0; i < length; ++i) {
232 if (2 * error >= -dy) {
236 if (2 * error <= dx) {
287 const Color& color) {
323 const Color& color) {
342 int dx = (1 + 2 * x) * e2 * e2;
354 err += dx += 2 * r2 * r2;
358 err += dy += 2 * r1 * r1;
387 const Color& color) {
406 int dx = (1 + 2 * x) * e2 * e2;
411 for (
int xx = x1 + x; xx <= x1 - x; ++xx) {
418 err += dx += 2 * r2 * r2;
422 err += dy += 2 * r1 * r1;
427 for (
int yy = y1 - y; yy <= y1 + y; ++yy) {
467void Canvas::DrawBlockOn(
int x,
int y) {
472 Cell& cell = storage_[XY{x / 2, y / 2}];
473 if (cell.type != CellType::kBlock) {
474 cell.content.character =
" ";
475 cell.type = CellType::kBlock;
478 const uint8_t bit = (x % 2) * 2 + y % 2;
479 uint8_t value = g_map_block_inversed.at(cell.content.character);
481 cell.content.character = g_map_block[value];
491 Cell& cell = storage_[XY{x / 2, y / 4}];
492 if (cell.type != CellType::kBlock) {
494 cell.type = CellType::kBlock;
498 const uint8_t bit = (y % 2) * 2 + x % 2;
499 uint8_t value = g_map_block_inversed.at(cell.content.
character);
500 value &= ~(1U << bit);
501 cell.content.
character = g_map_block[value];
511 Cell& cell = storage_[XY{x / 2, y / 4}];
512 if (cell.type != CellType::kBlock) {
514 cell.type = CellType::kBlock;
518 const uint8_t bit = (y % 2) * 2 + x % 2;
519 uint8_t value = g_map_block_inversed.at(cell.content.
character);
521 cell.content.
character = g_map_block[value];
558 const int dx = std::abs(x2 - x1);
559 const int dy = std::abs(y2 - y1);
560 const int sx = x1 < x2 ? 1 : -1;
561 const int sy = y1 < y2 ? 1 : -1;
562 const int length = std::max(dx, dy);
564 if (!IsIn(x1, y1) && !IsIn(x2, y2)) {
567 if (dx + dx > width_ * height_) {
572 for (
int i = 0; i < length; ++i) {
574 if (2 * error >= -dy) {
578 if (2 * error <= dx) {
629 const Color& color) {
665 const Color& color) {
686 int dx = (1 + 2 * x) * e2 * e2;
691 DrawBlock(x1 - x, 2 * (y1 + y),
true, s);
692 DrawBlock(x1 + x, 2 * (y1 + y),
true, s);
693 DrawBlock(x1 + x, 2 * (y1 - y),
true, s);
694 DrawBlock(x1 - x, 2 * (y1 - y),
true, s);
698 err += dx += 2 * r2 * r2;
702 err += dy += 2 * r1 * r1;
731 const Color& color) {
752 int dx = (1 + 2 * x) * e2 * e2;
757 for (
int xx = x1 + x; xx <= x1 - x; ++xx) {
764 err += dx += 2 * r2 * r2;
768 err += dy += 2 * r1 * r1;
773 for (
int yy = y1 + y; yy <= y1 - y; ++yy) {
794 const std::string& value,
795 const Color& color) {
806 const std::string& value,
813 Cell& cell = storage_[XY{x / 2, y / 4}];
814 cell.type = CellType::kCell;
825void Canvas::DrawPixel(
int x,
int y,
const Pixel& p) {
826 Cell& cell = storage_[XY{x / 2, y / 4}];
827 cell.type = CellType::kCell;
840 const int dx_begin = std::max(0, -x);
841 const int dy_begin = std::max(0, -y);
842 const int dx_end = std::min(image.
dimx(), width_ - x);
843 const int dy_end = std::min(image.
dimy(), height_ - y);
845 for (
int dy = dy_begin; dy < dy_end; ++dy) {
846 for (
int dx = dx_begin; dx < dx_end; ++dx) {
847 Cell& cell = storage_[XY{
851 cell.type = CellType::kCell;
852 cell.content = image.
PixelAt(dx, dy);
859void Canvas::Style(
int x,
int y,
const Stylizer& style) {
861 style(storage_[XY{x / 2, y / 4}].content);
867class CanvasNodeBase :
public Node {
869 CanvasNodeBase() =
default;
871 void Render(Screen& screen)
override {
872 const Canvas& c =
canvas();
873 const int y_max = std::min(c.height() / 4, box_.y_max - box_.y_min + 1);
874 const int x_max = std::min(c.width() / 2, box_.x_max - box_.x_min + 1);
875 for (
int y = 0; y < y_max; ++y) {
876 for (
int x = 0; x < x_max; ++x) {
877 screen.PixelAt(box_.x_min + x, box_.y_min + y) = c.GetPixel(x, y);
882 virtual const Canvas&
canvas() = 0;
890 class Impl :
public CanvasNodeBase {
893 requirement_.min_x = (canvas_->width() + 1) / 2;
894 requirement_.min_y = (canvas_->height() + 3) / 4;
896 const Canvas& canvas()
final {
return *canvas_; }
899 return std::make_shared<Impl>(canvas);
907 class Impl :
public CanvasNodeBase {
909 Impl(
int width,
int height, std::function<
void(
Canvas&)> fn)
910 : width_(width), height_(height), fn_(std::move(fn)) {}
912 void ComputeRequirement()
final {
913 requirement_.min_x = (width_ + 1) / 2;
914 requirement_.min_y = (height_ + 3) / 4;
917 void Render(
Screen& screen)
final {
918 const int width = (box_.x_max - box_.x_min + 1) * 2;
919 const int height = (box_.y_max - box_.y_min + 1) * 4;
920 canvas_ =
Canvas(width, height);
922 CanvasNodeBase::Render(screen);
925 const Canvas& canvas()
final {
return canvas_; }
929 std::function<void(
Canvas&)> fn_;
931 return std::make_shared<Impl>(width, height, std::move(fn));
937 const int default_dim = 12;
938 return canvas(default_dim, default_dim, std::move(fn));
アダプター。不変オブジェクトを所有または参照します。
void DrawImage(int x, int y, const Image &)
定義済み画像を、指定された座標を左上隅として描画します 負の座標を指定して画像を自由に配置できます。 表示される部分のみが描画されます。
void DrawBlockLine(int x1, int y1, int x2, int y2)
ブロック文字で線を描画します。
void DrawPointEllipseFilled(int x, int y, int r1, int r2)
点字ドットで塗りつぶされた楕円を描画します。
void DrawPointLine(int x1, int y1, int x2, int y2)
点字ドットで線を描画します。
void DrawText(int x, int y, const std::string &value, const Color &color)
テキストを描画します。
std::function< void(Pixel &)> Stylizer
void DrawPointCircleFilled(int x, int y, int radius)
点字ドットで塗りつぶされた円を描画します。
void DrawPointOn(int x, int y)
点字ドットを描画します。
void DrawPointOff(int x, int y)
点字ドットを消去します。
Pixel GetPixel(int x, int y) const
セルの内容を取得します。
void DrawBlockEllipseFilled(int x1, int y1, int r1, int r2)
ブロック文字で塗りつぶされた楕円を描画します。
void DrawPointEllipse(int x, int y, int r1, int r2)
点字ドットで楕円を描画します。
void DrawPoint(int x, int y, bool value)
点字ドットを描画します。
void DrawBlockEllipse(int x1, int y1, int r1, int r2)
ブロック文字で楕円を描画します。
void DrawBlockToggle(int x, int y)
ブロックを切り替えます。塗りつぶされている場合は消去され、空の場合は塗りつぶされます。
void DrawBlockCircle(int x1, int y1, int radius)
ブロック文字で円を描画します。
void DrawBlockCircleFilled(int x1, int y1, int radius)
ブロック文字で塗りつぶされた円を描画します。
void DrawPointCircle(int x, int y, int radius)
点字ドットで円を描画します。
void DrawBlockOff(int x, int y)
ブロックを消去します。
void DrawBlock(int x, int y, bool value)
ブロックを描画します。
void DrawPointToggle(int x, int y)
点字ドットを切り替えます。塗りつぶされたものは消去され、それ以外は描画されます。
void Render(Screen &screen, const Element &element)
要素をftxui::Screenに表示します。
Decorator color(Color)
前景色を使用して装飾します。
Canvasは、描画操作に関連付けられた描画可能なバッファです。
Pixel & PixelAt(int x, int y)
指定された位置のセル (ピクセル) にアクセスします。
Colorは、ターミナルユーザーインターフェースにおける色を表すクラスです。
Unicode文字とそれに関連付けられたスタイル。
std::shared_ptr< Node > Element
std::vector< std::string > Utf8ToGlyphs(const std::string &input)
Element canvas(ConstRef< Canvas >)
CanvasまたはCanvasへの参照から要素を生成します。