textDraw

Utility for drawing diagram in unicode with a json file format
git clone https://noulin.net/git/textDraw.git
Log | Files | Refs

textDraw.c (24115B)


      1 #! /usr/bin/env sheepy
      2 /* or direct path to sheepy: #! /usr/local/bin/sheepy */
      3 
      4 /* Libsheepy documentation: https://spartatek.se/libsheepy/ */
      5 #include "libsheepyObject.h"
      6 #include "shpPackages/short/short.h"
      7 
      8 /*
      9 
     10 unicode symbols:
     11 https://www.codetable.net/Group/box-drawing
     12 https://www.codetable.net/Group/arrows
     13 
     14 border styles:
     15 space
     16 single
     17 double
     18 singleDouble
     19 doubleSingle
     20 classic
     21 heavy ━
     22 dash ╴
     23 heavyDash ╸
     24 doubleDash ╌
     25 heavyDoubleDash ╍
     26 trippleDash ┄
     27 heavyTrippleDash ┅
     28 quadrupleDash ┈
     29 heavyQuadrupleDash ┉
     30 arcCorner ╭
     31 
     32 line intersections
     33     34 	Box Drawings Light Down And Right 		┌ 	┌
     35     36 	Box Drawings Down Light And Right Heavy 		┍ 	┍
     37     38 	Box Drawings Down Heavy And Right Light 		┎ 	┎
     39     40 	Box Drawings Heavy Down And Right 		┏ 	┏
     41     42 	Box Drawings Light Down And Left 		┐ 	┐
     43     44 	Box Drawings Down Light And Left Heavy 		┑ 	┑
     45     46 	Box Drawings Down Heavy And Left Light 		┒ 	┒
     47     48 	Box Drawings Heavy Down And Left 		┓ 	┓
     49     50 	Box Drawings Light Up And Right 		└ 	└
     51     52 	Box Drawings Up Light And Right Heavy 		┕ 	┕
     53     54 	Box Drawings Up Heavy And Right Light 		┖ 	┖
     55     56 	Box Drawings Heavy Up And Right 		┗ 	┗
     57     58 	Box Drawings Light Up And Left 		┘ 	┘
     59     60 	Box Drawings Up Light And Left Heavy 		┙ 	┙
     61     62 	Box Drawings Up Heavy And Left Light 		┚ 	┚
     63     64 	Box Drawings Heavy Up And Left 		┛ 	┛
     65     66 	Box Drawings Light Vertical And Right 		├ 	├
     67     68 	Box Drawings Vertical Light And Right Heavy 		┝ 	┝
     69     70 	Box Drawings Up Heavy And Right Down Light 		┞ 	┞
     71     72 	Box Drawings Down Heavy And Right Up Light 		┟ 	┟
     73     74 	Box Drawings Vertical Heavy And Right Light 		┠ 	┠
     75     76 	Box Drawings Down Light And Right Up Heavy 		┡ 	┡
     77     78 	Box Drawings Up Light And Right Down Heavy 		┢ 	┢
     79     80 	Box Drawings Heavy Vertical And Right 		┣ 	┣
     81     82 	Box Drawings Light Vertical And Left 		┤ 	┤
     83     84 	Box Drawings Vertical Light And Left Heavy 		┥ 	┥
     85     86 	Box Drawings Up Heavy And Left Down Light 		┦ 	┦
     87     88 	Box Drawings Down Heavy And Left Up Light 		┧ 	┧
     89     90 	Box Drawings Vertical Heavy And Left Light 		┨ 	┨
     91     92 	Box Drawings Down Light And Left Up Heavy 		┩ 	┩
     93     94 	Box Drawings Up Light And Left Down Heavy 		┪ 	┪
     95     96 	Box Drawings Heavy Vertical And Left 		┫ 	┫
     97     98 	Box Drawings Light Down And Horizontal 		┬ 	┬
     99    100 	Box Drawings Left Heavy And Right Down Light 		┭ 	┭
    101    102 	Box Drawings Right Heavy And Left Down Light 		┮ 	┮
    103    104 	Box Drawings Down Light And Horizontal Heavy 		┯ 	┯
    105    106 	Box Drawings Down Heavy And Horizontal Light 		┰ 	┰
    107    108 	Box Drawings Right Light And Left Down Heavy 		┱ 	┱
    109    110 	Box Drawings Left Light And Right Down Heavy 		┲ 	┲
    111    112 	Box Drawings Heavy Down And Horizontal 		┳ 	┳
    113    114 	Box Drawings Light Up And Horizontal 		┴ 	┴
    115    116 	Box Drawings Left Heavy And Right Up Light 		┵ 	┵
    117    118 	Box Drawings Right Heavy And Left Up Light 		┶ 	┶
    119    120 	Box Drawings Up Light And Horizontal Heavy 		┷ 	┷
    121    122 	Box Drawings Up Heavy And Horizontal Light 		┸ 	┸
    123    124 	Box Drawings Right Light And Left Up Heavy 		┹ 	┹
    125    126 	Box Drawings Left Light And Right Up Heavy 		┺ 	┺
    127    128 	Box Drawings Heavy Up And Horizontal 		┻ 	┻
    129    130 	Box Drawings Vertical Single And Right Double 		╞ 	╞
    131    132 	Box Drawings Vertical Double And Right Single 		╟ 	╟
    133    134 	Box Drawings Double Vertical And Right 		╠ 	╠
    135    136 	Box Drawings Vertical Single And Left Double 		╡ 	╡
    137    138 	Box Drawings Vertical Double And Left Single 		╢ 	╢
    139    140 	Box Drawings Double Vertical And Left 		╣ 	╣
    141    142 	Box Drawings Down Single And Horizontal Double 		╤ 	╤
    143    144 	Box Drawings Down Double And Horizontal Single 		╥ 	╥
    145    146 	Box Drawings Double Down And Horizontal 		╦ 	╦
    147    148 	Box Drawings Up Single And Horizontal Double 		╧ 	╧
    149    150 	Box Drawings Up Double And Horizontal Single 		╨ 	╨
    151    152 	Box Drawings Double Up And Horizontal 		╩ 	╩
    153 
    154 geometric shape
    155    156   Black Left-Pointing Triangle
    157    158   Black Up-Pointing Triangle
    159    160   Black Right-Pointing Triangle
    161    162   Black Down-Pointing Triangle
    163    164 	White Left-Pointing Small Triangle 		◃ 	◃
    165    166 	White Up-Pointing Small Triangle 		▵ 	▵
    167    168   White Right-Pointing Small Triangle
    169    170 	White Down-Pointing Small Triangle 		▿ 	▿
    171    172 	White Left-Pointing Triangle 		◁ 	◁
    173    174 	White Up-Pointing Triangle 		△ 	△
    175    176 	White Right-Pointing Triangle 		▷ 	▷
    177    178 	White Down-Pointing Triangle 		▽ 	▽
    179    180 	Black Left-Pointing Small Triangle 		◂ 	◂
    181    182 	Black Up-Pointing Small Triangle 		▴ 	▴
    183    184 	Black Right-Pointing Small Triangle 		▸ 	▸
    185    186 	Black Down-Pointing Small Triangle 		▾ 	▾
    187    188 	White Right-Pointing Pointer 		▻ 	▻
    189    190 	White Left-Pointing Pointer
    191 
    192 arrow
    193    194 	Leftwards Arrow 	← 	← 	←
    195    196 	Upwards Arrow 	↑ 	↑ 	↑
    197    198 	Rightwards Arrow 	→ 	→ 	→
    199    200 	Downwards Arrow 	↓ 	↓ 	↓
    201    202 	Leftwards Arrow With Stroke 		↚ 	↚
    203    204 	Rightwards Arrow With Stroke 		↛ 	↛
    205    206 	Leftwards Wave Arrow 		↜ 	↜
    207    208 	Rightwards Wave Arrow 		↝ 	↝
    209    210 	Leftwards Two Headed Arrow 		↞ 	↞
    211    212 	Upwards Two Headed Arrow 		↟ 	↟
    213    214 	Rightwards Two Headed Arrow 		↠ 	↠
    215    216 	Downwards Two Headed Arrow 		↡ 	↡
    217    218 	Leftwards Arrow With Tail 		↢ 	↢
    219    220 	Rightwards Arrow With Tail 		↣ 	↣
    221    222 	Leftwards Arrow From Bar 		↤ 	↤
    223    224 	Upwards Arrow From Bar 		↥ 	↥
    225    226 	Rightwards Arrow From Bar 		↦ 	↦
    227    228 	Downwards Arrow From Bar 		↧ 	↧
    229    230 	Leftwards Harpoon Over Rightwards Harpoon 		⇋ 	⇋
    231    232 	Rightwards Harpoon Over Leftwards Harpoon 		⇌ 	⇌
    233    234 	Leftwards Double Arrow With Stroke 		⇍ 	⇍
    235    236 	Left Right Double Arrow With Stroke 		⇎ 	⇎
    237    238 	Rightwards Double Arrow With Stroke 		⇏ 	⇏
    239    240 	Leftwards Double Arrow 	⇐ 	⇐ 	⇐
    241    242 	Upwards Double Arrow 	⇑ 	⇑ 	⇑
    243    244 	Rightwards Double Arrow 	⇒ 	⇒ 	⇒
    245    246 	Downwards Double Arrow 	⇓ 	⇓ 	⇓
    247    248 	Leftwards Squiggle Arrow 		⇜ 	⇜
    249    250 	Rightwards Squiggle Arrow 		⇝ 	⇝
    251    252 	Upwards Arrow With Double Stroke 		⇞ 	⇞
    253    254 	Downwards Arrow With Double Stroke 		⇟ 	⇟
    255    256 	Leftwards Dashed Arrow 		⇠ 	⇠
    257    258 	Upwards Dashed Arrow 		⇡ 	⇡
    259    260 	Rightwards Dashed Arrow 		⇢ 	⇢
    261    262 	Downwards Dashed Arrow 		⇣ 	⇣
    263    264 	Leftwards Arrow To Bar 		⇤ 	⇤
    265    266 	Rightwards Arrow To Bar 		⇥ 	⇥
    267    268 	Right Arrow With Small Circle 		⇴ 	⇴
    269    270 	Leftwards Arrow With Vertical Stroke 		⇷ 	⇷
    271    272 	Rightwards Arrow With Vertical Stroke 		⇸ 	⇸
    273    274 	Left Right Arrow With Vertical Stroke 		⇹ 	⇹
    275    276 	Leftwards Arrow With Double Vertical Stroke 		⇺ 	⇺
    277    278 	Rightwards Arrow With Double Vertical Stroke 		⇻ 	⇻
    279    280 	Left Right Arrow With Double Vertical Stroke 		⇼ 	⇼
    281    282 	Leftwards Open-Headed Arrow 		⇽ 	⇽
    283    284 	Rightwards Open-Headed Arrow 		⇾ 	⇾
    285    286 	Left Right Open-Headed Arrow 		⇿ 	⇿
    287 
    288 */
    289 
    290 
    291 
    292 /* enable/disable logging */
    293 /* #undef pLog */
    294 /* #define pLog(...) */
    295 
    296 typ struct {
    297   char *value;
    298   char *color;
    299   char *bgColor;
    300 } screenElementt;
    301 
    302 typ struct {
    303   char *topLeft;
    304   char *topRight;
    305   char *bottomLeft;
    306   char *bottomRight;
    307   char *horizontal;
    308   char *vertical;
    309 } borderStylet;
    310 
    311 // space
    312 internal borderStylet spaceBorderStyle = {
    313 .topLeft= " ",
    314 .topRight= " ",
    315 .bottomLeft= " ",
    316 .bottomRight= " ",
    317 .horizontal= " ",
    318 .vertical= " "
    319 };
    320 
    321 // single
    322 internal borderStylet singleBorderStyle = {
    323 .topLeft= "┌",
    324 .topRight= "┐",
    325 .bottomLeft= "└",
    326 .bottomRight= "┘",
    327 .horizontal= "─",
    328 .vertical= "│"
    329 };
    330 
    331 // double
    332 internal borderStylet doubleBorderStyle = {
    333 .topLeft= "╔",
    334 .topRight= "╗",
    335 .bottomLeft= "╚",
    336 .bottomRight= "╝",
    337 .horizontal= "═",
    338 .vertical= "║"
    339 };
    340 
    341 // single-double
    342 internal borderStylet singleDoubleBorderStyle = {
    343 .topLeft= "╓",
    344 .topRight= "╖",
    345 .bottomLeft= "╙",
    346 .bottomRight= "╜",
    347 .horizontal= "─",
    348 .vertical= "║"
    349 };
    350 
    351 // double-single
    352 internal borderStylet doubleSingleBorderStyle = {
    353 .topLeft= "╒",
    354 .topRight= "╕",
    355 .bottomLeft= "╘",
    356 .bottomRight= "╛",
    357 .horizontal= "═",
    358 .vertical= "│"
    359 };
    360 
    361 
    362 // classic
    363 internal borderStylet classicBorderStyle = {
    364 .topLeft= "+",
    365 .topRight= "+",
    366 .bottomLeft= "+",
    367 .bottomRight= "+",
    368 .horizontal= "-",
    369 .vertical= "|"
    370 };
    371 
    372 // heavy
    373 internal borderStylet heavyBorderStyle = {
    374 .topLeft= "┏",
    375 .topRight= "┓",
    376 .bottomLeft= "┗",
    377 .bottomRight= "┛",
    378 .horizontal= "━",
    379 .vertical= "┃"
    380 };
    381 
    382 // dash
    383 internal borderStylet dashBorderStyle = {
    384 .topLeft= "┌",
    385 .topRight= "┐",
    386 .bottomLeft= "└",
    387 .bottomRight= "┘",
    388 .horizontal= "╴",
    389 .vertical= "╵"
    390 };
    391 
    392 // heavyDash
    393 internal borderStylet heavyDashBorderStyle = {
    394 .topLeft= "┏",
    395 .topRight= "┓",
    396 .bottomLeft= "┗",
    397 .bottomRight= "┛",
    398 .horizontal= "╸",
    399 .vertical= "╹"
    400 };
    401 
    402 // doubleDash
    403 internal borderStylet doubleDashBorderStyle = {
    404 .topLeft= "┌",
    405 .topRight= "┐",
    406 .bottomLeft= "└",
    407 .bottomRight= "┘",
    408 .horizontal= "╌",
    409 .vertical= "╎"
    410 };
    411 
    412 // heavyDoubleDash
    413 internal borderStylet heavyDoubleDashBorderStyle = {
    414 .topLeft= "┏",
    415 .topRight= "┓",
    416 .bottomLeft= "┗",
    417 .bottomRight= "┛",
    418 .horizontal= "╍",
    419 .vertical= "╏"
    420 };
    421 
    422 // trippleDash
    423 internal borderStylet trippleDashBorderStyle = {
    424 .topLeft= "┌",
    425 .topRight= "┐",
    426 .bottomLeft= "└",
    427 .bottomRight= "┘",
    428 .horizontal= "┄",
    429 .vertical= "┆"
    430 };
    431 
    432 // heavyTrippleDash
    433 internal borderStylet heavyTrippleDashBorderStyle = {
    434 .topLeft= "┏",
    435 .topRight= "┓",
    436 .bottomLeft= "┗",
    437 .bottomRight= "┛",
    438 .horizontal= "┅",
    439 .vertical= "┇"
    440 };
    441 
    442 // quadrupleDash
    443 internal borderStylet quadrupleDashBorderStyle = {
    444 .topLeft= "┌",
    445 .topRight= "┐",
    446 .bottomLeft= "└",
    447 .bottomRight= "┘",
    448 .horizontal= "┈",
    449 .vertical= "┊"
    450 };
    451 
    452 // heavyQuadrupleDash
    453 internal borderStylet heavyQuadrupleDashBorderStyle = {
    454 .topLeft= "┏",
    455 .topRight= "┓",
    456 .bottomLeft= "┗",
    457 .bottomRight= "┛",
    458 .horizontal= "┉",
    459 .vertical= "┋"
    460 };
    461 
    462 char *cross[3][3] = {
    463   {"┼", "╪", "┿"},
    464   {"╫", "╬", "╋"},
    465   {"╂", "╋", "╋"}
    466 };
    467 
    468 bool showDiagram(smallJsont *dia) {
    469 
    470   // Steps
    471   // find diagram size
    472   // show diagram
    473   // allocate screen
    474   // draw objects
    475 
    476   u32 w = 0 ,h = 0; // diagram width and height
    477   if (!dia) ret no;
    478   // find diagram size
    479   iter(dia, E) {
    480     cast(smallDictt*,e,E);
    481     if (!isOSmallDictG(e)) ret no; // all diagram elements are dicts
    482     // compute element edges
    483     u32 ew = 0, eh = 0;
    484     if (eqG($(e,"type"), "verticalLine")) {
    485       ew = u$(e,"at");
    486       eh = maxV(u$(e,"start"), u$(e, "stop"));
    487     }
    488     elif (eqG($(e,"type"), "horizontalLine")) {
    489       ew = maxV(u$(e,"start"), u$(e, "stop"));
    490       eh = u$(e,"at");
    491     }
    492     elif (eqG($(e,"type"), "text")) {
    493       ew = u$(e, "x") + strlen($(e,"text"));
    494       eh = u$(e, "y");
    495     }
    496     elif (eqG($(e,"type"), "box")) {
    497       ew = u$(e, "xx");
    498       eh = u$(e, "yy");
    499     }
    500     w = maxV(w, ew);
    501     h = maxV(h, eh);
    502   }
    503   // allocate screen
    504   inc w; inc h;
    505   screenElementt *screen = calloc(1, w * h * sizeof(screenElementt));
    506   // draw objects
    507   iter(dia, E) {
    508     cast(smallDictt*,e,E);
    509 
    510     cleanCharP(color)   = null;
    511     cleanCharP(bgColor) = null;
    512     #define oColor(colr, value)\
    513       if (icEqG($(e, "color"), colr)) {\
    514         color    = strdup(value);\
    515       }
    516     #define oBgColor(colr, value)\
    517       if (icEqG($(e, "bgColor"), colr)) {\
    518         bgColor    = strdup(value);\
    519       }
    520     #define oHexColor(colr, opt, fgbgc)\
    521       if ($(e, colr) && $(e, colr)[0] == '#') {\
    522         /* hex color */\
    523         char *c  = $(e, colr);\
    524         /* check if color is 0 */\
    525         bool is0 = true;\
    526         size_t i = 1;\
    527         while(c[i]) if (c[i++] != '0') {is0 = false; break;}\
    528         \
    529         opt = BLK;\
    530         if (!is0) {\
    531           /* convert color string to int */\
    532           cleanCharP(s) = catS("0x", &c[1]);\
    533           u32 c = parseHex(s);\
    534           if (!c) {\
    535             /* invalid hex number */\
    536             opt = strdup("");\
    537           }\
    538           else {\
    539             opt = formatS("\x1b["fgbgc";2;%d;%d;%dm", c>>16, (c&0xFF00)>>8, c&0xFF);\
    540           }\
    541         }\
    542       }
    543     oColor      ( "black"   , BLK)
    544     else oColor ( "red"     , RED)
    545     else oColor ( "green"   , GRN)
    546     else oColor ( "yellow"  , YLW)
    547     else oColor ( "blue"    , BLU)
    548     else oColor ( "magenta" , MGT)
    549     else oColor ( "cyan"    , CYN)
    550     else oColor ( "white"   , BLD WHT)
    551     else oColor ( "gray"    , WHT)
    552     else oHexColor("color", color, "38")
    553     oBgColor      ( "black"   , BGBLK)
    554     else oBgColor ( "red"     , BGRED)
    555     else oBgColor ( "green"   , BGGRN)
    556     else oBgColor ( "yellow"  , BGYLW)
    557     else oBgColor ( "blue"    , BGBLU)
    558     else oBgColor ( "magenta" , BGMGT)
    559     else oBgColor ( "cyan"    , BGCYN)
    560     else oBgColor ( "white"   , BGWHT) // TODO RGB?
    561     else oBgColor ( "gray"    , BGWHT)
    562     else oHexColor("bgColor", bgColor, "48")
    563 
    564     if (eqG($(e,"type"), "verticalLine")) {
    565       char *line;
    566 			#define lineStyle(style, value)\
    567         if (icEqG($(e, "style"), style)) {\
    568           line = value;\
    569         }
    570            lineStyle("single",             "│")
    571       else lineStyle("double",             "║")
    572       else lineStyle("heavy",              "┃")
    573       else lineStyle("dash",               "╵")
    574       else lineStyle("heavyDash",          "╹")
    575       else lineStyle("doubleDash",         "╎")
    576       else lineStyle("heavyDoubleDash",    "╏")
    577       else lineStyle("trippleDash",        "┆")
    578       else lineStyle("heavyTrippleDash",   "┇")
    579       else lineStyle("quadrupleDash",      "┊")
    580       else lineStyle("heavyQuadrupleDash", "┋")
    581       screenElementt *ptr = screen + u$(e, "at") + u$(e, "start") * w;
    582       ptr->value          = strdup(orS($(e,"startEdge"), line));
    583       if (color)   ptr->color          = strdup(color);
    584       if (bgColor) ptr->bgColor        = strdup(bgColor);
    585       ptr                 = screen + u$(e, "at") + u$(e, "stop") * w;
    586       ptr->value          = strdup(orS($(e,"stopEdge"), line));
    587       if (color)   ptr->color          = strdup(color);
    588       if (bgColor) ptr->bgColor        = strdup(bgColor);
    589       u32 y               = minV(u$(e, "start"), u$(e, "stop")) + 1/*edge*/;
    590       u32 yy              = maxV(u$(e, "start"), u$(e, "stop"));
    591       rangeFrom(i, y, yy) {
    592         ptr          = screen + u$(e, "at") + i * w;
    593         ptr->value   = strdup(line);
    594         if (color)   ptr->color   = strdup(color);
    595         if (bgColor) ptr->bgColor = strdup(bgColor);
    596       }
    597     }
    598     elif (eqG($(e,"type"), "horizontalLine")) {
    599       char *line;
    600            lineStyle("single",             "─")
    601       else lineStyle("double",             "═")
    602       else lineStyle("heavy",              "━")
    603       else lineStyle("dash",               "╴")
    604       else lineStyle("heavyDash",          "╸")
    605       else lineStyle("doubleDash",         "╌")
    606       else lineStyle("heavyDoubleDash",    "╍")
    607       else lineStyle("trippleDash",        "┄")
    608       else lineStyle("heavyTrippleDash",   "┅")
    609       else lineStyle("quadrupleDash",      "┈")
    610       else lineStyle("heavyQuadrupleDash", "┉")
    611       screenElementt *ptr = screen + u$(e, "start") + u$(e, "at") * w;
    612       ptr->value          = strdup(orS($(e,"startEdge"), line));
    613       if (color)   ptr->color          = strdup(color);
    614       if (bgColor) ptr->bgColor        = strdup(bgColor);
    615       ptr                 = screen + u$(e, "stop") + u$(e, "at") * w;
    616       ptr->value          = strdup(orS($(e,"stopEdge"), line));
    617       if (color)   ptr->color          = strdup(color);
    618       if (bgColor) ptr->bgColor        = strdup(bgColor);
    619       u32 x               = minV(u$(e, "start"), u$(e, "stop")) + 1/*edge*/;
    620       u32 xx              = maxV(u$(e, "start"), u$(e, "stop"));
    621       rangeFrom(i, x, xx) {
    622         ptr          = screen + i + u$(e, "at") * w;
    623         ptr->value   = strdup(line);
    624         if (color)   ptr->color   = strdup(color);
    625         if (bgColor) ptr->bgColor = strdup(bgColor);
    626       }
    627     }
    628     elif (eqG($(e,"type"), "text")) {
    629       screenElementt *ptr = screen + u$(e, "x") + u$(e, "y") * w;
    630       const char *s       = $(e,"text");
    631       char val[2]         = init0Var;
    632       loop(lenG(s)) {
    633         val[0]       = *s;
    634         ptr->value   = strdup(val);
    635         if (color)   ptr->color   = strdup(color);
    636         if (bgColor) ptr->bgColor = strdup(bgColor);
    637         inc s;
    638         inc ptr;
    639       }
    640     }
    641     elif (eqG($(e,"type"), "box")) {
    642       borderStylet borderStyle;
    643       #define oborderStyle(style, value)\
    644         if (icEqG($(e, "style"), style)) {\
    645           borderStyle = value;\
    646         }
    647            oborderStyle("space"             , spaceBorderStyle)
    648       else oborderStyle("single"            , singleBorderStyle)
    649       else oborderStyle("double"            , doubleBorderStyle)
    650       else oborderStyle("single-double"     , singleDoubleBorderStyle)
    651       else oborderStyle("double-single"     , doubleSingleBorderStyle)
    652       else oborderStyle("classic"           , classicBorderStyle)
    653       else oborderStyle("heavy"             , heavyBorderStyle)
    654       else oborderStyle("dash"              , dashBorderStyle)
    655       else oborderStyle("heavyDash"         , heavyDashBorderStyle)
    656       else oborderStyle("doubleDash"        , doubleDashBorderStyle)
    657       else oborderStyle("heavyDoubleDash"   , heavyDoubleDashBorderStyle)
    658       else oborderStyle("trippleDash"       , trippleDashBorderStyle)
    659       else oborderStyle("heavyTrippleDash"  , heavyTrippleDashBorderStyle)
    660       else oborderStyle("quadrupleDash"     , quadrupleDashBorderStyle)
    661       else oborderStyle("heavyQuadrupleDash", heavyQuadrupleDashBorderStyle)
    662 
    663       if (getG(e, rtBool, "arcCorner")) {
    664         borderStyle.topLeft     = "╭";
    665         borderStyle.topRight    = "╮";
    666         borderStyle.bottomLeft  = "╰";
    667         borderStyle.bottomRight = "╯";
    668       }
    669 
    670       screenElementt *ptr = screen + u$(e, "x") + u$(e, "y") * w;
    671       ptr->value          = strdup(borderStyle.topLeft);
    672       if (color)   ptr->color          = strdup(color);
    673       if (bgColor) ptr->bgColor        = strdup(bgColor);
    674       ptr                 = screen + u$(e, "xx") + u$(e, "y") * w;
    675       ptr->value          = strdup(borderStyle.topRight);
    676       if (color)   ptr->color          = strdup(color);
    677       if (bgColor) ptr->bgColor        = strdup(bgColor);
    678       ptr                 = screen + u$(e, "x") + u$(e, "yy") * w;
    679       ptr->value          = strdup(borderStyle.bottomLeft);
    680       if (color)   ptr->color          = strdup(color);
    681       if (bgColor) ptr->bgColor        = strdup(bgColor);
    682       ptr                 = screen + u$(e, "xx") + u$(e, "yy") * w;
    683       ptr->value          = strdup(borderStyle.bottomRight);
    684       if (color)   ptr->color          = strdup(color);
    685       if (bgColor) ptr->bgColor        = strdup(bgColor);
    686       rangeFrom(i, u$(e, "x")+1, u$(e, "xx")) {
    687         ptr          = screen + i + u$(e, "y") * w;
    688         ptr->value   = strdup(borderStyle.horizontal);
    689         if (color)   ptr->color   = strdup(color);
    690         if (bgColor) ptr->bgColor = strdup(bgColor);
    691         ptr          = screen + i + u$(e, "yy") * w;
    692         ptr->value   = strdup(borderStyle.horizontal);
    693         if (color)   ptr->color   = strdup(color);
    694         if (bgColor) ptr->bgColor = strdup(bgColor);
    695       }
    696       rangeFrom(i, u$(e, "y")+1, u$(e, "yy")) {
    697         ptr          = screen + u$(e, "x") + i * w;
    698         ptr->value   = strdup(borderStyle.vertical);
    699         if (color)   ptr->color   = strdup(color);
    700         if (bgColor) ptr->bgColor = strdup(bgColor);
    701         ptr          = screen + u$(e, "xx") + i * w;
    702         ptr->value   = strdup(borderStyle.vertical);
    703         if (color)   ptr->color   = strdup(color);
    704         if (bgColor) ptr->bgColor = strdup(bgColor);
    705       }
    706       // box inside
    707       rangeFrom(j, u$(e,"y")+1, u$(e,"yy")) {
    708         rangeFrom(i, u$(e,"x")+1, u$(e,"xx")) {
    709           ptr          = screen + i + j * w;
    710           ptr->value   = strdup(" ");
    711           if (color)   ptr->color   = strdup(color);
    712           if (bgColor) ptr->bgColor = strdup(bgColor);
    713         }
    714       }
    715     }
    716   }
    717   // add line crosses
    718   // loop on vertical lines: v
    719   //   loop on horizontal lines: u
    720   //     choose cross character
    721   createSmallJson(vertical);
    722   createSmallJson(horizontal);
    723   setsoG(&vertical, getsoG(dia));
    724   setsoG(&horizontal, getsoG(dia));
    725   u8 vidx, hidx; // indexes in cross[][]
    726   iter(&vertical, V) {
    727     cast(smallDictt*,v,V);
    728     if (not eqG($(v,"type"), "verticalLine")) continue;
    729 
    730     iter(&horizontal, U) {
    731       cast(smallDictt*,u,U);
    732       if (not eqG($(u,"type"), "horizontalLine")) continue;
    733 
    734       // check if the lines cross
    735       var vY  = minV(u$(v, "start"), u$(v, "stop"));
    736       var vYY = maxV(u$(v, "start"), u$(v, "stop"));
    737       var uX  = minV(u$(u, "start"), u$(u, "stop"));
    738       var uXX = maxV(u$(u, "start"), u$(u, "stop"));
    739       if (u$(v, "at") <= uX or u$(v, "at") >= uXX) continue; // outside
    740       if (u$(u, "at") <= vY or u$(u, "at") >= vYY) continue; // outside
    741 
    742       #define vCross(style, value)\
    743         if (icEqG($(v, "style"), style)) {\
    744           vidx = value;\
    745         }
    746       vCross     ("single",             0)
    747       else vCross("double",             1)
    748       else vCross("heavy",              2)
    749       else vCross("dash",               0)
    750       else vCross("heavyDash",          2)
    751       else vCross("doubleDash",         0)
    752       else vCross("heavyDoubleDash",    2)
    753       else vCross("trippleDash",        0)
    754       else vCross("heavyTrippleDash",   2)
    755       else vCross("quadrupleDash",      0)
    756       else vCross("heavyQuadrupleDash", 2)
    757       else vidx = 0;
    758 
    759       #define hCross(style, value)\
    760         if (icEqG($(u, "style"), style)) {\
    761           hidx = value;\
    762         }
    763       hCross     ("single",             0)
    764       else hCross("double",             1)
    765       else hCross("heavy",              2)
    766       else hCross("dash",               0)
    767       else hCross("heavyDash",          2)
    768       else hCross("doubleDash",         0)
    769       else hCross("heavyDoubleDash",    2)
    770       else hCross("trippleDash",        0)
    771       else hCross("heavyTrippleDash",   2)
    772       else hCross("quadrupleDash",      0)
    773       else hCross("heavyQuadrupleDash", 2)
    774       else hidx = 0;
    775 
    776       screenElementt *ptr = screen + u$(v, "at") + u$(u, "at") * w;
    777       free(ptr->value);
    778       ptr->value          = strdup(cross[vidx][hidx]);
    779 
    780     }
    781   }
    782   // show diagram
    783   range(j, h) {
    784     range(i, w) {
    785       screenElementt *ptr = screen + i + j * w;
    786       if (ptr->value) printf("%s%s%s"RST, nS(ptr->color), nS(ptr->bgColor), ptr->value);
    787       else printf(" ");
    788     }
    789     put
    790   }
    791   range(j, h) {
    792     range(i, w) {
    793       screenElementt *ptr = screen + i + j * w;
    794       free(ptr->value);
    795       free(ptr->color);
    796       free(ptr->bgColor);
    797     }
    798   }
    799   free(screen);
    800 }
    801 
    802 int main(int ARGC, char** ARGV) {
    803 
    804   initLibsheepy(ARGV[0]);
    805   setLogMode(LOG_FUNC);
    806   //openProgLogFile();
    807   setLogSymbols(LOG_UTF8);
    808   //disableLibsheepyErrorLogs;
    809 
    810   if (ARGC < 2) {
    811     logI("Usage: textDraw file");
    812   }
    813 
    814   cleanAllocateSmallJson(dia);
    815   readFileG(dia, ARGV[1]);
    816 
    817   showDiagram(dia);
    818 }
    819 // vim: set expandtab ts=2 sw=2: