canvas.cpp
ftxui/dom/canvas.hpp
algorithm
cmath
cstdint
cstdlib
ftxui/screen/color.hpp
functional
map
memory
utility
vector
ftxui/dom/elements.hpp
ftxui/dom/node.hpp
ftxui/dom/requirement.hpp
ftxui/screen/box.hpp
ftxui/screen/image.hpp
ftxui/screen/pixel.hpp
ftxui/screen/screen.hpp
ftxui/screen/string.hpp
ftxui/util/ref.hpp
ftxui/dom/canvas.hpp
ftxui/dom/deprecated.hpp
ftxui/dom/direction.hpp
ftxui/dom/elements.hpp
ftxui/dom/flexbox_config.hpp
ftxui/dom/linear_gradient.hpp
ftxui/dom/node.hpp
ftxui/dom/requirement.hpp
ftxui/dom/selection.hpp
ftxui/screen/box.hpp
ftxui/screen/color.hpp
ftxui/screen/image.hpp
ftxui/screen/pixel.hpp
ftxui/screen/screen.hpp
ftxui/screen/string.hpp
ftxui/screen/terminal.hpp
ftxui/util/autoreset.hpp
ftxui/util/ref.hpp
src/ftxui/dom/canvas.cpp
algorithm
cmath
cstddef
cstdint
cstdlib
ftxui/dom/take_any_args.hpp
functional
map
memory
optional
sstream
string
unordered_map
utility
variant
vector
ftxui

    //Copyright2021ArthurSonzogni.Allrightsreserved.
    //UseofthissourcecodeisgovernedbytheMITlicensethatcanbefoundin
    //theLICENSEfile.
    #include"ftxui/dom/canvas.hpp"

    #include<algorithm>//formax,min
    #include<cmath>//forabs
    #include<cstdint>//foruint8_t
    #include<cstdlib>//forabs
    #include<ftxui/screen/color.hpp>//forColor
    #include<functional>//forfunction
    #include<map>//formap
    #include<memory>//formake_shared
    #include<utility>//formove,pair
    #include<vector>//forvector

    #include"ftxui/dom/elements.hpp"//forElement,canvas
    #include"ftxui/dom/node.hpp"//forNode
    #include"ftxui/dom/requirement.hpp"//forRequirement
    #include"ftxui/screen/box.hpp"//forBox
    #include"ftxui/screen/image.hpp"//forImage
    #include"ftxui/screen/pixel.hpp"//forPixel
    #include"ftxui/screen/screen.hpp"//forPixel,Screen
    #include"ftxui/screen/string.hpp"//forUtf8ToGlyphs
    #include"ftxui/util/ref.hpp"//forConstRef

    namespaceftxui{

    namespace{

    //BaseUTF8pattern:
    //111000101010000010000000//empty

    //Patternfortheindividualdots:
    //┌──────┬───────┐
    //│dot1│dot4│
    //├──────┼───────┤
    //│dot2│dot5│
    //├──────┼───────┤
    //│dot3│dot6│
    //├──────┼───────┤
    //│dot0-1│dot0-2│
    //└──────┴───────┘
    //111000101010000010000001//dot1
    //111000101010000010000010//dot2
    //111000101010000010000100//dot3
    //111000101010000110000000//dot0-1
    //111000101010000010001000//dot4
    //111000101010000010010000//dot5
    //111000101010000010100000//dot6
    //111000101010001010000000//dot0-2

    //NOLINTNEXTLINE
    uint8_tg_map_braille[2][4][2]={
    {
    {0b00000000,0b00000001},//NOLINT|dot1
    {0b00000000,0b00000010},//NOLINT|dot2
    {0b00000000,0b00000100},//NOLINT|dot3
    {0b00000001,0b00000000},//NOLINT|dot0-1
    },
    {
    {0b00000000,0b00001000},//NOLINT|dot4
    {0b00000000,0b00010000},//NOLINT|dot5
    {0b00000000,0b00100000},//NOLINT|dot6
    {0b00000010,0b00000000},//NOLINT|dot0-2
    },
    };

    //NOLINTNEXTLINE
    std::vector<std::string>g_map_block={
    "","▘","▖","▌","▝","▀","▞","▛",
    "▗","▚","▄","▙","▐","▜","▟","█",
    };

    //NOLINTNEXTLINE
    conststd::map<std::string,uint8_t>g_map_block_inversed={
    {"",0b0000},{"▘",0b0001},{"▖",0b0010},{"▌",0b0011},
    {"▝",0b0100},{"▀",0b0101},{"▞",0b0110},{"▛",0b0111},
    {"▗",0b1000},{"▚",0b1001},{"▄",0b1010},{"▙",0b1011},
    {"▐",0b1100},{"▜",0b1101},{"▟",0b1110},{"█",0b1111},
    };

    constexprautonostyle=[](Pixel&/*pixel*/){};

    }//namespace

    ///@briefConstructor.
    ///@paramwidththewidthofthecanvas.Acellisa2x4brailledot.
    ///@paramheighttheheightofthecanvas.Acellisa2x4brailledot.
    Canvas::Canvas(intwidth,intheight)
    :width_(width),
    height_(height),
    storage_(width_*height_/8/*NOLINT*/){}

    ///@briefGetthecontentofacell.
    ///@paramxthexcoordinateofthecell.
    ///@paramytheycoordinateofthecell.
    PixelCanvas::GetPixel(intx,inty)const{
    autoit=storage_.find(XY{x,y});
    return(it==storage_.end())?Pixel():it->second.content;
    }

    ///@briefDrawabrailledot.
    ///@paramxthexcoordinateofthedot.
    ///@paramytheycoordinateofthedot.
    ///@paramvaluewhetherthedotisfilledornot.
    voidCanvas::DrawPoint(intx,inty,boolvalue){
    DrawPoint(x,y,value,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawabrailledot.
    ///@paramxthexcoordinateofthedot.
    ///@paramytheycoordinateofthedot.
    ///@paramvaluewhetherthedotisfilledornot.
    ///@paramcolorthecolorofthedot.
    voidCanvas::DrawPoint(intx,inty,boolvalue,constColor&color){
    DrawPoint(x,y,value,[color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawabrailledot.
    ///@paramxthexcoordinateofthedot.
    ///@paramytheycoordinateofthedot.
    ///@paramvaluewhetherthedotisfilledornot.
    ///@paramstylethestyleofthecell.
    voidCanvas::DrawPoint(intx,inty,boolvalue,constStylizer&style){
    Style(x,y,style);
    if(value){
    DrawPointOn(x,y);
    }else{
    DrawPointOff(x,y);
    }
    }

    ///@briefDrawabrailledot.
    ///@paramxthexcoordinateofthedot.
    ///@paramytheycoordinateofthedot.
    voidCanvas::DrawPointOn(intx,inty){
    if(!IsIn(x,y)){
    return;
    }
    Cell&cell=storage_[XY{x/2,y/4}];
    if(cell.type!=CellType::kBraille){
    cell.content.character="⠀";//3bytes.
    cell.type=CellType::kBraille;
    }

    cell.content.character[1]|=g_map_braille[x%2][y%4][0];//NOLINT
    cell.content.character[2]|=g_map_braille[x%2][y%4][1];//NOLINT
    }

    ///@briefEraseabrailledot.
    ///@paramxthexcoordinateofthedot.
    ///@paramytheycoordinateofthedot.
    voidCanvas::DrawPointOff(intx,inty){
    if(!IsIn(x,y)){
    return;
    }
    Cell&cell=storage_[XY{x/2,y/4}];
    if(cell.type!=CellType::kBraille){
    cell.content.character="⠀";//3byt
    cell.type=CellType::kBraille;
    }

    cell.content.character[1]&=~(g_map_braille[x%2][y%4][0]);//NOLINT
    cell.content.character[2]&=~(g_map_braille[x%2][y%4][1]);//NOLINT
    }

    ///@briefToggleabrailledot.Afilledonewillbeerased,andtheotherwill
    ///bedrawn.
    ///@paramxthexcoordinateofthedot.
    ///@paramytheycoordinateofthedot.
    voidCanvas::DrawPointToggle(intx,inty){
    if(!IsIn(x,y)){
    return;
    }
    Cell&cell=storage_[XY{x/2,y/4}];
    if(cell.type!=CellType::kBraille){
    cell.content.character="⠀";//3byt
    cell.type=CellType::kBraille;
    }

    cell.content.character[1]^=g_map_braille[x%2][y%4][0];//NOLINT
    cell.content.character[2]^=g_map_braille[x%2][y%4][1];//NOLINT
    }

    ///@briefDrawalinemadeofbrailledots.
    ///@paramx1thexcoordinateofthefirstdot.
    ///@paramy1theycoordinateofthefirstdot.
    ///@paramx2thexcoordinateoftheseconddot.
    ///@paramy2theycoordinateoftheseconddot.
    voidCanvas::DrawPointLine(intx1,inty1,intx2,inty2){
    DrawPointLine(x1,y1,x2,y2,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawalinemadeofbrailledots.
    ///@paramx1thexcoordinateofthefirstdot.
    ///@paramy1theycoordinateofthefirstdot.
    ///@paramx2thexcoordinateoftheseconddot.
    ///@paramy2theycoordinateoftheseconddot.
    ///@paramcolorthecoloroftheline.
    voidCanvas::DrawPointLine(intx1,inty1,intx2,inty2,constColor&color){
    DrawPointLine(x1,y1,x2,y2,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawalinemadeofbrailledots.
    ///@paramx1thexcoordinateofthefirstdot.
    ///@paramy1theycoordinateofthefirstdot.o
    ///@paramx2thexcoordinateoftheseconddot.
    ///@paramy2theycoordinateoftheseconddot.
    ///@paramstylethestyleoftheline.
    voidCanvas::DrawPointLine(intx1,
    inty1,
    intx2,
    inty2,
    constStylizer&style){
    constintdx=std::abs(x2-x1);
    constintdy=std::abs(y2-y1);
    constintsx=x1<x2?1:-1;
    constintsy=y1<y2?1:-1;
    constintlength=std::max(dx,dy);

    if(!IsIn(x1,y1)&&!IsIn(x2,y2)){
    return;
    }
    if(dx+dx>width_*height_){
    return;
    }

    interror=dx-dy;
    for(inti=0;i<length;++i){
    DrawPoint(x1,y1,true,style);
    if(2*error>=-dy){
    error-=dy;
    x1+=sx;
    }
    if(2*error<=dx){
    error+=dx;
    y1+=sy;
    }
    }
    DrawPoint(x2,y2,true,style);
    }

    ///@briefDrawacirclemadeofbrailledots.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    voidCanvas::DrawPointCircle(intx,inty,intradius){
    DrawPointCircle(x,y,radius,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawacirclemadeofbrailledots.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramcolorthecolorofthecircle.
    voidCanvas::DrawPointCircle(intx,inty,intradius,constColor&color){
    DrawPointCircle(x,y,radius,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawacirclemadeofbrailledots.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramstylethestyleofthecircle.
    voidCanvas::DrawPointCircle(intx,inty,intradius,constStylizer&style){
    DrawPointEllipse(x,y,radius,radius,style);
    }

    ///@briefDrawafilledcirclemadeofbrailledots.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    voidCanvas::DrawPointCircleFilled(intx,inty,intradius){
    DrawPointCircleFilled(x,y,radius,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawafilledcirclemadeofbrailledots.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramcolorthecolorofthecircle.
    voidCanvas::DrawPointCircleFilled(intx,
    inty,
    intradius,
    constColor&color){
    DrawPointCircleFilled(x,y,radius,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawafilledcirclemadeofbrailledots.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramstylethestyleofthecircle.
    voidCanvas::DrawPointCircleFilled(intx,
    inty,
    intradius,
    constStylizer&style){
    DrawPointEllipseFilled(x,y,radius,radius,style);
    }

    ///@briefDrawanellipsemadeofbrailledots.
    ///@paramxthexcoordinateofthecenteroftheellipse.
    ///@paramytheycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    voidCanvas::DrawPointEllipse(intx,inty,intr1,intr2){
    DrawPointEllipse(x,y,r1,r2,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawanellipsemadeofbrailledots.
    ///@paramxthexcoordinateofthecenteroftheellipse.
    ///@paramytheycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramcolorthecoloroftheellipse.
    voidCanvas::DrawPointEllipse(intx,
    inty,
    intr1,
    intr2,
    constColor&color){
    DrawPointEllipse(x,y,r1,r2,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawanellipsemadeofbrailledots.
    ///@paramx1thexcoordinateofthecenteroftheellipse.
    ///@paramy1theycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramsthestyleoftheellipse.
    voidCanvas::DrawPointEllipse(intx1,
    inty1,
    intr1,
    intr2,
    constStylizer&s){
    intx=-r1;
    inty=0;
    inte2=r2;
    intdx=(1+2*x)*e2*e2;
    intdy=x*x;
    interr=dx+dy;

    do{//NOLINT
    DrawPoint(x1-x,y1+y,true,s);
    DrawPoint(x1+x,y1+y,true,s);
    DrawPoint(x1+x,y1-y,true,s);
    DrawPoint(x1-x,y1-y,true,s);
    e2=2*err;
    if(e2>=dx){
    x++;
    err+=dx+=2*r2*r2;
    }
    if(e2<=dy){
    y++;
    err+=dy+=2*r1*r1;
    }
    }while(x<=0);

    while(y++<r2){
    DrawPoint(x1,y1+y,true,s);
    DrawPoint(x1,y1-y,true,s);
    }
    }

    ///@briefDrawafilledellipsemadeofbrailledots.
    ///@paramx1thexcoordinateofthecenteroftheellipse.
    ///@paramy1theycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    voidCanvas::DrawPointEllipseFilled(intx1,inty1,intr1,intr2){
    DrawPointEllipseFilled(x1,y1,r1,r2,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawafilledellipsemadeofbrailledots.
    ///@paramx1thexcoordinateofthecenteroftheellipse.
    ///@paramy1theycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramcolorthecoloroftheellipse.
    voidCanvas::DrawPointEllipseFilled(intx1,
    inty1,
    intr1,
    intr2,
    constColor&color){
    DrawPointEllipseFilled(x1,y1,r1,r2,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawafilledellipsemadeofbrailledots.
    ///@paramx1thexcoordinateofthecenteroftheellipse.
    ///@paramy1theycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramsthestyleoftheellipse.
    voidCanvas::DrawPointEllipseFilled(intx1,
    inty1,
    intr1,
    intr2,
    constStylizer&s){
    intx=-r1;
    inty=0;
    inte2=r2;
    intdx=(1+2*x)*e2*e2;
    intdy=x*x;
    interr=dx+dy;

    do{//NOLINT
    for(intxx=x1+x;xx<=x1-x;++xx){
    DrawPoint(xx,y1+y,true,s);
    DrawPoint(xx,y1-y,true,s);
    }
    e2=2*err;
    if(e2>=dx){
    x++;
    err+=dx+=2*r2*r2;
    }
    if(e2<=dy){
    y++;
    err+=dy+=2*r1*r1;
    }
    }while(x<=0);

    while(y++<r2){
    for(intyy=y1-y;yy<=y1+y;++yy){
    DrawPoint(x1,yy,true,s);
    }
    }
    }

    ///@briefDrawablock.
    ///@paramxthexcoordinateoftheblock.
    ///@paramytheycoordinateoftheblock.
    ///@paramvaluewhethertheblockisfilledornot.
    voidCanvas::DrawBlock(intx,inty,boolvalue){
    DrawBlock(x,y,value,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawablock.
    ///@paramxthexcoordinateoftheblock.
    ///@paramytheycoordinateoftheblock.
    ///@paramvaluewhethertheblockisfilledornot.
    ///@paramcolorthecoloroftheblock.
    voidCanvas::DrawBlock(intx,inty,boolvalue,constColor&color){
    DrawBlock(x,y,value,[color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawablock.
    ///@paramxthexcoordinateoftheblock.
    ///@paramytheycoordinateoftheblock.
    ///@paramvaluewhethertheblockisfilledornot.
    ///@paramstylethestyleoftheblock.
    voidCanvas::DrawBlock(intx,inty,boolvalue,constStylizer&style){
    Style(x,y,style);
    if(value){
    DrawBlockOn(x,y);
    }else{
    DrawBlockOff(x,y);
    }
    }

    ///@briefDrawablock.
    ///@paramxthexcoordinateoftheblock.
    ///@paramytheycoordinateoftheblock.
    voidCanvas::DrawBlockOn(intx,inty){
    if(!IsIn(x,y)){
    return;
    }
    y/=2;
    Cell&cell=storage_[XY{x/2,y/2}];
    if(cell.type!=CellType::kBlock){
    cell.content.character="";
    cell.type=CellType::kBlock;
    }

    constuint8_tbit=(x%2)*2+y%2;
    uint8_tvalue=g_map_block_inversed.at(cell.content.character);
    value|=1U<<bit;
    cell.content.character=g_map_block[value];
    }

    ///@briefEraseablock.
    ///@paramxthexcoordinateoftheblock.
    ///@paramytheycoordinateoftheblock.
    voidCanvas::DrawBlockOff(intx,inty){
    if(!IsIn(x,y)){
    return;
    }
    Cell&cell=storage_[XY{x/2,y/4}];
    if(cell.type!=CellType::kBlock){
    cell.content.character="";
    cell.type=CellType::kBlock;
    }
    y/=2;

    constuint8_tbit=(y%2)*2+x%2;
    uint8_tvalue=g_map_block_inversed.at(cell.content.character);
    value&=~(1U<<bit);
    cell.content.character=g_map_block[value];
    }

    ///@briefToggleablock.Ifitisfilled,itwillbeerased.Ifitisempty,
    ///itwillbefilled.
    ///@paramxthexcoordinateoftheblock.
    ///@paramytheycoordinateoftheblock.
    voidCanvas::DrawBlockToggle(intx,inty){
    if(!IsIn(x,y)){
    return;
    }
    Cell&cell=storage_[XY{x/2,y/4}];
    if(cell.type!=CellType::kBlock){
    cell.content.character="";
    cell.type=CellType::kBlock;
    }
    y/=2;

    constuint8_tbit=(y%2)*2+x%2;
    uint8_tvalue=g_map_block_inversed.at(cell.content.character);
    value^=1U<<bit;
    cell.content.character=g_map_block[value];
    }

    ///@briefDrawalinemadeofblockcharacters.
    ///@paramx1thexcoordinateofthefirstpointoftheline.
    ///@paramy1theycoordinateofthefirstpointoftheline.
    ///@paramx2thexcoordinateofthesecondpointoftheline.
    ///@paramy2theycoordinateofthesecondpointoftheline.
    voidCanvas::DrawBlockLine(intx1,inty1,intx2,inty2){
    DrawBlockLine(x1,y1,x2,y2,[](Pixel&/*pixel*/){});
    }

    ///@briefDrawalinemadeofblockcharacters.
    ///@paramx1thexcoordinateofthefirstpointoftheline.
    ///@paramy1theycoordinateofthefirstpointoftheline.
    ///@paramx2thexcoordinateofthesecondpointoftheline.
    ///@paramy2theycoordinateofthesecondpointoftheline.
    ///@paramcolorthecoloroftheline.
    voidCanvas::DrawBlockLine(intx1,inty1,intx2,inty2,constColor&color){
    DrawBlockLine(x1,y1,x2,y2,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawalinemadeofblockcharacters.
    ///@paramx1thexcoordinateofthefirstpointoftheline.
    ///@paramy1theycoordinateofthefirstpointoftheline.
    ///@paramx2thexcoordinateofthesecondpointoftheline.
    ///@paramy2theycoordinateofthesecondpointoftheline.
    ///@paramstylethestyleoftheline.
    voidCanvas::DrawBlockLine(intx1,
    inty1,
    intx2,
    inty2,
    constStylizer&style){
    y1/=2;
    y2/=2;

    constintdx=std::abs(x2-x1);
    constintdy=std::abs(y2-y1);
    constintsx=x1<x2?1:-1;
    constintsy=y1<y2?1:-1;
    constintlength=std::max(dx,dy);

    if(!IsIn(x1,y1)&&!IsIn(x2,y2)){
    return;
    }
    if(dx+dx>width_*height_){
    return;
    }

    interror=dx-dy;
    for(inti=0;i<length;++i){
    DrawBlock(x1,y1*2,true,style);
    if(2*error>=-dy){
    error-=dy;
    x1+=sx;
    }
    if(2*error<=dx){
    error+=dx;
    y1+=sy;
    }
    }
    DrawBlock(x2,y2*2,true,style);
    }

    ///@briefDrawacirclemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    voidCanvas::DrawBlockCircle(intx,inty,intradius){
    DrawBlockCircle(x,y,radius,nostyle);
    }

    ///@briefDrawacirclemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramcolorthecolorofthecircle.
    voidCanvas::DrawBlockCircle(intx,inty,intradius,constColor&color){
    DrawBlockCircle(x,y,radius,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawacirclemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramstylethestyleofthecircle.
    voidCanvas::DrawBlockCircle(intx,inty,intradius,constStylizer&style){
    DrawBlockEllipse(x,y,radius,radius,style);
    }

    ///@briefDrawafilledcirclemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    voidCanvas::DrawBlockCircleFilled(intx,inty,intradius){
    DrawBlockCircleFilled(x,y,radius,nostyle);
    }

    ///@briefDrawafilledcirclemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramcolorthecolorofthecircle.
    voidCanvas::DrawBlockCircleFilled(intx,
    inty,
    intradius,
    constColor&color){
    DrawBlockCircleFilled(x,y,radius,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawafilledcirclemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenterofthecircle.
    ///@paramytheycoordinateofthecenterofthecircle.
    ///@paramradiustheradiusofthecircle.
    ///@paramsthestyleofthecircle.
    voidCanvas::DrawBlockCircleFilled(intx,
    inty,
    intradius,
    constStylizer&s){
    DrawBlockEllipseFilled(x,y,radius,radius,s);
    }

    ///@briefDrawanellipsemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenteroftheellipse.
    ///@paramytheycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    voidCanvas::DrawBlockEllipse(intx,inty,intr1,intr2){
    DrawBlockEllipse(x,y,r1,r2,nostyle);
    }

    ///@briefDrawanellipsemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenteroftheellipse.
    ///@paramytheycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramcolorthecoloroftheellipse.
    voidCanvas::DrawBlockEllipse(intx,
    inty,
    intr1,
    intr2,
    constColor&color){
    DrawBlockEllipse(x,y,r1,r2,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawanellipsemadeofblockcharacters.
    ///@paramx1thexcoordinateofthecenteroftheellipse.
    ///@paramy1theycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramsthestyleoftheellipse.
    voidCanvas::DrawBlockEllipse(intx1,
    inty1,
    intr1,
    intr2,
    constStylizer&s){
    y1/=2;
    r2/=2;
    intx=-r1;
    inty=0;
    inte2=r2;
    intdx=(1+2*x)*e2*e2;
    intdy=x*x;
    interr=dx+dy;

    do{//NOLINT
    DrawBlock(x1-x,2*(y1+y),true,s);
    DrawBlock(x1+x,2*(y1+y),true,s);
    DrawBlock(x1+x,2*(y1-y),true,s);
    DrawBlock(x1-x,2*(y1-y),true,s);
    e2=2*err;
    if(e2>=dx){
    x++;
    err+=dx+=2*r2*r2;
    }
    if(e2<=dy){
    y++;
    err+=dy+=2*r1*r1;
    }
    }while(x<=0);

    while(y++<r2){
    DrawBlock(x1,2*(y1+y),true,s);
    DrawBlock(x1,2*(y1-y),true,s);
    }
    }

    ///@briefDrawafilledellipsemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenteroftheellipse.
    ///@paramytheycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    voidCanvas::DrawBlockEllipseFilled(intx,inty,intr1,intr2){
    DrawBlockEllipseFilled(x,y,r1,r2,nostyle);
    }

    ///@briefDrawafilledellipsemadeofblockcharacters.
    ///@paramxthexcoordinateofthecenteroftheellipse.
    ///@paramytheycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramcolorthecoloroftheellipse.
    voidCanvas::DrawBlockEllipseFilled(intx,
    inty,
    intr1,
    intr2,
    constColor&color){
    DrawBlockEllipseFilled(x,y,r1,r2,
    [color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawafilledellipsemadeofblockcharacters.
    ///@paramx1thexcoordinateofthecenteroftheellipse.
    ///@paramy1theycoordinateofthecenteroftheellipse.
    ///@paramr1theradiusoftheellipsealongthexaxis.
    ///@paramr2theradiusoftheellipsealongtheyaxis.
    ///@paramsthestyleoftheellipse.
    voidCanvas::DrawBlockEllipseFilled(intx1,
    inty1,
    intr1,
    intr2,
    constStylizer&s){
    y1/=2;
    r2/=2;
    intx=-r1;
    inty=0;
    inte2=r2;
    intdx=(1+2*x)*e2*e2;
    intdy=x*x;
    interr=dx+dy;

    do{//NOLINT
    for(intxx=x1+x;xx<=x1-x;++xx){
    DrawBlock(xx,2*(y1+y),true,s);
    DrawBlock(xx,2*(y1-y),true,s);
    }
    e2=2*err;
    if(e2>=dx){
    x++;
    err+=dx+=2*r2*r2;
    }
    if(e2<=dy){
    y++;
    err+=dy+=2*r1*r1;
    }
    }while(x<=0);

    while(y++<r2){
    for(intyy=y1+y;yy<=y1-y;++yy){
    DrawBlock(x1,2*yy,true,s);
    }
    }
    }

    ///@briefDrawapieceoftext.
    ///@paramxthexcoordinateofthetext.
    ///@paramytheycoordinateofthetext.
    ///@paramvaluethetexttodraw.
    voidCanvas::DrawText(intx,inty,conststd::string&value){
    DrawText(x,y,value,nostyle);
    }

    ///@briefDrawapieceoftext.
    ///@paramxthexcoordinateofthetext.
    ///@paramytheycoordinateofthetext.
    ///@paramvaluethetexttodraw.
    ///@paramcolorthecolorofthetext.
    voidCanvas::DrawText(intx,
    inty,
    conststd::string&value,
    constColor&color){
    DrawText(x,y,value,[color](Pixel&p){p.foreground_color=color;});
    }

    ///@briefDrawapieceoftext.
    ///@paramxthexcoordinateofthetext.
    ///@paramytheycoordinateofthetext.
    ///@paramvaluethetexttodraw.
    ///@paramstylethestyleofthetext.
    voidCanvas::DrawText(intx,
    inty,
    conststd::string&value,
    constStylizer&style){
    for(constauto&it:Utf8ToGlyphs(value)){
    if(!IsIn(x,y)){
    x+=2;
    continue;
    }
    Cell&cell=storage_[XY{x/2,y/4}];
    cell.type=CellType::kCell;
    cell.content.character=it;
    style(cell.content);
    x+=2;
    }
    }

    ///@briefDirectlydrawapredefinedpixelatthegivencoordinate
    ///@paramxthexcoordinateofthepixel.
    ///@paramytheycoordinateofthepixel.
    ///@parampthepixeltodraw.
    voidCanvas::DrawPixel(intx,inty,constPixel&p){
    Cell&cell=storage_[XY{x/2,y/4}];
    cell.type=CellType::kCell;
    cell.content=p;
    }

    ///@briefDrawapredefinedimage,withtop-leftcorneratthegivencoordinate
    ///Youcansupplynegativecoordinatestoaligntheimagehoweveryoulike-
    ///onlythe'visible'portionwillbedrawn
    ///@paramxthexcoordinatecorrespondingtothetop-leftcorneroftheimage.
    ///@paramytheycoordinatecorrespondingtothetop-leftcorneroftheimage.
    ///@paramimagetheimagetodraw.
    voidCanvas::DrawImage(intx,inty,constImage&image){
    x/=2;
    y/=4;
    constintdx_begin=std::max(0,-x);
    constintdy_begin=std::max(0,-y);
    constintdx_end=std::min(image.dimx(),width_-x);
    constintdy_end=std::min(image.dimy(),height_-y);

    for(intdy=dy_begin;dy<dy_end;++dy){
    for(intdx=dx_begin;dx<dx_end;++dx){
    Cell&cell=storage_[XY{
    x+dx,
    y+dy,
    }];
    cell.type=CellType::kCell;
    cell.content=image.PixelAt(dx,dy);
    }
    }
    }

    ///@briefModifyapixelatagivenlocation.
    ///@paramstyleafunctionthatmodifiesthepixel.
    voidCanvas::Style(intx,inty,constStylizer&style){
    if(IsIn(x,y)){
    style(storage_[XY{x/2,y/4}].content);
    }
    }

    namespace{

    classCanvasNodeBase:publicNode{
    public:
    CanvasNodeBase()=default;

    voidRender(Screen&screen)override{
    constCanvas&c=canvas();
    constinty_max=std::min(c.height()/4,box_.y_max-box_.y_min+1);
    constintx_max=std::min(c.width()/2,box_.x_max-box_.x_min+1);
    for(inty=0;y<y_max;++y){
    for(intx=0;x<x_max;++x){
    screen.PixelAt(box_.x_min+x,box_.y_min+y)=c.GetPixel(x,y);
    }
    }
    }

    virtualconstCanvas&canvas()=0;
    };

    }//namespace

    ///@briefProduceanelementfromaCanvas,orareferencetoaCanvas.
    //NOLINTNEXTLINE
    Elementcanvas(ConstRef<Canvas>canvas){
    classImpl:publicCanvasNodeBase{
    public:
    explicitImpl(ConstRef<Canvas>canvas):canvas_(std::move(canvas)){
    requirement_.min_x=(canvas_->width()+1)/2;
    requirement_.min_y=(canvas_->height()+3)/4;
    }
    constCanvas&canvas()final{return*canvas_;}
    ConstRef<Canvas>canvas_;
    };
    returnstd::make_shared<Impl>(canvas);
    }

    ///@briefProduceanelementdrawingacanvasofrequestedsize.
    ///@paramwidththewidthofthecanvas.
    ///@paramheighttheheightofthecanvas.
    ///@paramfnafunctiondrawingthecanvas.
    Elementcanvas(intwidth,intheight,std::function<void(Canvas&)>fn){
    classImpl:publicCanvasNodeBase{
    public:
    Impl(intwidth,intheight,std::function<void(Canvas&)>fn)
    :width_(width),height_(height),fn_(std::move(fn)){}

    voidComputeRequirement()final{
    requirement_.min_x=(width_+1)/2;
    requirement_.min_y=(height_+3)/4;
    }

    voidRender(Screen&screen)final{
    constintwidth=(box_.x_max-box_.x_min+1)*2;
    constintheight=(box_.y_max-box_.y_min+1)*4;
    canvas_=Canvas(width,height);
    fn_(canvas_);
    CanvasNodeBase::Render(screen);
    }

    constCanvas&canvas()final{returncanvas_;}
    Canvascanvas_;
    intwidth_;
    intheight_;
    std::function<void(Canvas&)>fn_;
    };
    returnstd::make_shared<Impl>(width,height,std::move(fn));
    }

    ///@briefProduceanelementdrawingacanvas.
    ///@paramfnafunctiondrawingthecanvas.
    Elementcanvas(std::function<void(Canvas&)>fn){
    constintdefault_dim=12;
    returncanvas(default_dim,default_dim,std::move(fn));
    }

    }//namespaceftxui