We now have a full map that's basically the same mapping system from Roguish. There's a bug right now where it needs you to move once to calc the light and it's not being centered, but it does work.
parent
55b67dcf5d
commit
d798d154ae
@ -0,0 +1,371 @@ |
|||||||
|
|
||||||
|
#line 1 "ansi_parser.rl" |
||||||
|
#include <fmt/core.h> |
||||||
|
#include <string_view> |
||||||
|
#include "dbc.hpp" |
||||||
|
#include <SFML/Graphics.hpp> |
||||||
|
#include "ansi_parser.hpp" |
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
using namespace fmt; |
||||||
|
|
||||||
|
|
||||||
|
#line 122 "ansi_parser.rl" |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#line 13 "ansi_parser.cpp" |
||||||
|
static const char _ansi_parser_actions[] = { |
||||||
|
0, 1, 0, 1, 3, 1, 4, 1,
|
||||||
|
5, 1, 6, 1, 7, 1, 8, 1,
|
||||||
|
9, 1, 10, 1, 11, 1, 15, 1,
|
||||||
|
16, 2, 1, 12, 2, 1, 13, 2,
|
||||||
|
6, 7, 2, 16, 5, 3, 1, 14,
|
||||||
|
2 |
||||||
|
}; |
||||||
|
|
||||||
|
static const char _ansi_parser_key_offsets[] = { |
||||||
|
0, 0, 1, 2, 11, 12, 14, 17,
|
||||||
|
18, 22, 23, 27, 28, 29, 30, 31,
|
||||||
|
33, 36, 38, 41, 43, 46, 47, 50,
|
||||||
|
51, 52, 53, 54, 55 |
||||||
|
}; |
||||||
|
|
||||||
|
static const int _ansi_parser_trans_keys[] = { |
||||||
|
27, 91, 48, 49, 50, 51, 52, 55,
|
||||||
|
57, 53, 54, 109, 48, 109, 34, 48,
|
||||||
|
55, 109, 50, 52, 55, 109, 109, 49,
|
||||||
|
56, 57, 109, 109, 59, 50, 59, 48,
|
||||||
|
57, 59, 48, 57, 48, 57, 59, 48,
|
||||||
|
57, 48, 57, 109, 48, 57, 109, 56,
|
||||||
|
57, 109, 59, 50, 109, 109, 27, 27,
|
||||||
|
0 |
||||||
|
}; |
||||||
|
|
||||||
|
static const char _ansi_parser_single_lengths[] = { |
||||||
|
0, 1, 1, 7, 1, 2, 3, 1,
|
||||||
|
4, 1, 4, 1, 1, 1, 1, 0,
|
||||||
|
1, 0, 1, 0, 1, 1, 3, 1,
|
||||||
|
1, 1, 1, 1, 1 |
||||||
|
}; |
||||||
|
|
||||||
|
static const char _ansi_parser_range_lengths[] = { |
||||||
|
0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 1,
|
||||||
|
1, 1, 1, 1, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0 |
||||||
|
}; |
||||||
|
|
||||||
|
static const char _ansi_parser_index_offsets[] = { |
||||||
|
0, 0, 2, 4, 13, 15, 18, 22,
|
||||||
|
24, 29, 31, 36, 38, 40, 42, 44,
|
||||||
|
46, 49, 51, 54, 56, 59, 61, 65,
|
||||||
|
67, 69, 71, 73, 75 |
||||||
|
}; |
||||||
|
|
||||||
|
static const char _ansi_parser_trans_targs[] = { |
||||||
|
2, 1, 3, 0, 4, 5, 8, 10,
|
||||||
|
22, 26, 6, 7, 0, 28, 0, 6,
|
||||||
|
28, 0, 7, 7, 7, 0, 28, 0,
|
||||||
|
7, 7, 9, 28, 0, 28, 0, 11,
|
||||||
|
12, 21, 28, 0, 28, 0, 13, 0,
|
||||||
|
14, 0, 15, 0, 16, 0, 17, 16,
|
||||||
|
0, 18, 0, 19, 18, 0, 20, 0,
|
||||||
|
28, 20, 0, 28, 0, 23, 25, 28,
|
||||||
|
0, 24, 0, 14, 0, 28, 0, 28,
|
||||||
|
0, 2, 1, 2, 1, 0 |
||||||
|
}; |
||||||
|
|
||||||
|
static const char _ansi_parser_trans_actions[] = { |
||||||
|
0, 7, 0, 0, 21, 21, 21, 21,
|
||||||
|
21, 21, 21, 21, 0, 31, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 17, 0, 15, 0, 0,
|
||||||
|
0, 0, 0, 0, 19, 0, 0, 0,
|
||||||
|
3, 0, 0, 0, 1, 0, 25, 0,
|
||||||
|
0, 1, 0, 28, 0, 0, 1, 0,
|
||||||
|
37, 0, 0, 9, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 5, 0, 11, 0, 13,
|
||||||
|
0, 0, 7, 23, 34, 0 |
||||||
|
}; |
||||||
|
|
||||||
|
static const char _ansi_parser_eof_actions[] = { |
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 23 |
||||||
|
}; |
||||||
|
|
||||||
|
static const int ansi_parser_start = 27; |
||||||
|
static const int ansi_parser_first_final = 27; |
||||||
|
static const int ansi_parser_error = 0; |
||||||
|
|
||||||
|
static const int ansi_parser_en_main = 27; |
||||||
|
|
||||||
|
|
||||||
|
#line 125 "ansi_parser.rl" |
||||||
|
|
||||||
|
#include <ftxui/screen/terminal.hpp> |
||||||
|
|
||||||
|
ANSIParser::ANSIParser(sf::Color default_fg, sf::Color default_bg) : |
||||||
|
$default_fg(default_fg), |
||||||
|
$default_bg(default_bg) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb) { |
||||||
|
const wchar_t *start = NULL; |
||||||
|
int cs = 0; |
||||||
|
unsigned int value = 0; |
||||||
|
const wchar_t *p = codes.data(); |
||||||
|
const wchar_t *pe = p + codes.size(); |
||||||
|
const wchar_t *eof = pe; |
||||||
|
sf::Color bgcolor($default_bg); |
||||||
|
sf::Color color($default_fg); |
||||||
|
sf::Color* target = &color; |
||||||
|
|
||||||
|
|
||||||
|
#line 120 "ansi_parser.cpp" |
||||||
|
{ |
||||||
|
cs = ansi_parser_start; |
||||||
|
} |
||||||
|
|
||||||
|
#line 146 "ansi_parser.rl" |
||||||
|
|
||||||
|
#line 123 "ansi_parser.cpp" |
||||||
|
{ |
||||||
|
int _klen; |
||||||
|
unsigned int _trans; |
||||||
|
const char *_acts; |
||||||
|
unsigned int _nacts; |
||||||
|
const int *_keys; |
||||||
|
|
||||||
|
if ( p == pe ) |
||||||
|
goto _test_eof; |
||||||
|
if ( cs == 0 ) |
||||||
|
goto _out; |
||||||
|
_resume: |
||||||
|
_keys = _ansi_parser_trans_keys + _ansi_parser_key_offsets[cs]; |
||||||
|
_trans = _ansi_parser_index_offsets[cs]; |
||||||
|
|
||||||
|
_klen = _ansi_parser_single_lengths[cs]; |
||||||
|
if ( _klen > 0 ) { |
||||||
|
const int *_lower = _keys; |
||||||
|
const int *_mid; |
||||||
|
const int *_upper = _keys + _klen - 1; |
||||||
|
while (1) { |
||||||
|
if ( _upper < _lower ) |
||||||
|
break; |
||||||
|
|
||||||
|
_mid = _lower + ((_upper-_lower) >> 1); |
||||||
|
if ( (*p) < *_mid ) |
||||||
|
_upper = _mid - 1; |
||||||
|
else if ( (*p) > *_mid ) |
||||||
|
_lower = _mid + 1; |
||||||
|
else { |
||||||
|
_trans += (unsigned int)(_mid - _keys); |
||||||
|
goto _match; |
||||||
|
} |
||||||
|
} |
||||||
|
_keys += _klen; |
||||||
|
_trans += _klen; |
||||||
|
} |
||||||
|
|
||||||
|
_klen = _ansi_parser_range_lengths[cs]; |
||||||
|
if ( _klen > 0 ) { |
||||||
|
const int *_lower = _keys; |
||||||
|
const int *_mid; |
||||||
|
const int *_upper = _keys + (_klen<<1) - 2; |
||||||
|
while (1) { |
||||||
|
if ( _upper < _lower ) |
||||||
|
break; |
||||||
|
|
||||||
|
_mid = _lower + (((_upper-_lower) >> 1) & ~1); |
||||||
|
if ( (*p) < _mid[0] ) |
||||||
|
_upper = _mid - 2; |
||||||
|
else if ( (*p) > _mid[1] ) |
||||||
|
_lower = _mid + 2; |
||||||
|
else { |
||||||
|
_trans += (unsigned int)((_mid - _keys)>>1); |
||||||
|
goto _match; |
||||||
|
} |
||||||
|
} |
||||||
|
_trans += _klen; |
||||||
|
} |
||||||
|
|
||||||
|
_match: |
||||||
|
cs = _ansi_parser_trans_targs[_trans]; |
||||||
|
|
||||||
|
if ( _ansi_parser_trans_actions[_trans] == 0 ) |
||||||
|
goto _again; |
||||||
|
|
||||||
|
_acts = _ansi_parser_actions + _ansi_parser_trans_actions[_trans]; |
||||||
|
_nacts = (unsigned int) *_acts++; |
||||||
|
while ( _nacts-- > 0 ) |
||||||
|
{ |
||||||
|
switch ( *_acts++ ) |
||||||
|
{ |
||||||
|
case 0: |
||||||
|
#line 14 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
start = p; |
||||||
|
} |
||||||
|
break; |
||||||
|
case 1: |
||||||
|
#line 18 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
value = 0; |
||||||
|
size_t len = p - start; |
||||||
|
dbc::check(start[0] != '-', "negative numbers not supported"); |
||||||
|
|
||||||
|
switch(len) { |
||||||
|
case 10: value += (start[len-10] - '0') * 1000000000; [[fallthrough]]; |
||||||
|
case 9: value += (start[len- 9] - '0') * 100000000; [[fallthrough]]; |
||||||
|
case 8: value += (start[len- 8] - '0') * 10000000; [[fallthrough]]; |
||||||
|
case 7: value += (start[len- 7] - '0') * 1000000; [[fallthrough]]; |
||||||
|
case 6: value += (start[len- 6] - '0') * 100000; [[fallthrough]]; |
||||||
|
case 5: value += (start[len- 5] - '0') * 10000; [[fallthrough]]; |
||||||
|
case 4: value += (start[len- 4] - '0') * 1000; [[fallthrough]]; |
||||||
|
case 3: value += (start[len- 3] - '0') * 100; [[fallthrough]]; |
||||||
|
case 2: value += (start[len- 2] - '0') * 10; [[fallthrough]]; |
||||||
|
case 1: value += (start[len- 1] - '0'); |
||||||
|
break; |
||||||
|
default: |
||||||
|
dbc::sentinel("can't process > 10 digits"); |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
case 2: |
||||||
|
#line 40 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 3: |
||||||
|
#line 43 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
target = &color; |
||||||
|
} |
||||||
|
break; |
||||||
|
case 4: |
||||||
|
#line 46 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
target = &bgcolor; |
||||||
|
} |
||||||
|
break; |
||||||
|
case 5: |
||||||
|
#line 50 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
write_cb((*p)); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 6: |
||||||
|
#line 54 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
color = $default_fg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 7: |
||||||
|
#line 58 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
bgcolor = $default_bg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 8: |
||||||
|
#line 62 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
color = $default_bg; |
||||||
|
bgcolor = $default_fg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 9: |
||||||
|
#line 67 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
color = $default_fg; |
||||||
|
bgcolor = $default_bg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 10: |
||||||
|
#line 72 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
color = sf::Color(100,100,100); |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 11: |
||||||
|
#line 76 "ansi_parser.rl" |
||||||
|
{ |
||||||
|
color = sf::Color::Red; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
break; |
||||||
|
case 12: |
||||||
|
#line 81 "ansi_parser.rl" |
||||||
|
{ target->r = value; } |
||||||
|
break; |
||||||
|
case 13: |
||||||
|
#line 82 "ansi_parser.rl" |
||||||
|
{ target->g = value; } |
||||||
|
break; |
||||||
|
case 14: |
||||||
|
#line 83 "ansi_parser.rl" |
||||||
|
{ target->b = value; } |
||||||
|
break; |
||||||
|
case 15: |
||||||
|
#line 84 "ansi_parser.rl" |
||||||
|
{ value = 0; } |
||||||
|
break; |
||||||
|
case 16: |
||||||
|
#line 85 "ansi_parser.rl" |
||||||
|
{} |
||||||
|
break; |
||||||
|
#line 296 "ansi_parser.cpp" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_again: |
||||||
|
if ( cs == 0 ) |
||||||
|
goto _out; |
||||||
|
if ( ++p != pe ) |
||||||
|
goto _resume; |
||||||
|
_test_eof: {} |
||||||
|
if ( p == eof ) |
||||||
|
{ |
||||||
|
const char *__acts = _ansi_parser_actions + _ansi_parser_eof_actions[cs]; |
||||||
|
unsigned int __nacts = (unsigned int) *__acts++; |
||||||
|
while ( __nacts-- > 0 ) { |
||||||
|
switch ( *__acts++ ) { |
||||||
|
case 16: |
||||||
|
#line 85 "ansi_parser.rl" |
||||||
|
{} |
||||||
|
break; |
||||||
|
#line 314 "ansi_parser.cpp" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_out: {} |
||||||
|
} |
||||||
|
|
||||||
|
#line 147 "ansi_parser.rl" |
||||||
|
|
||||||
|
bool good = pe - p == 0; |
||||||
|
|
||||||
|
if(!good) { |
||||||
|
p -= 10; |
||||||
|
// dear cthuhlu, save me from the pain that is wstring
|
||||||
|
for(int i = 0; i < 100; i++) { |
||||||
|
try { |
||||||
|
print("{}", p[i] == 0x1B ? '^' : char(p[i])); |
||||||
|
} catch(...) { |
||||||
|
print("?=", int(p[i])); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return good; |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
#pragma once |
||||||
|
#include <string_view> |
||||||
|
#include <SFML/Graphics.hpp> |
||||||
|
#include <codecvt> |
||||||
|
#include <functional> |
||||||
|
|
||||||
|
typedef std::function<void(sf::Color bgcolor, sf::Color color)> ColorCB; |
||||||
|
|
||||||
|
typedef std::function<void(wchar_t ch)> WriteCB; |
||||||
|
|
||||||
|
class ANSIParser { |
||||||
|
sf::Color $default_fg; |
||||||
|
sf::Color $default_bg; |
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter; |
||||||
|
|
||||||
|
public: |
||||||
|
ANSIParser(sf::Color default_fg, sf::Color default_bg); |
||||||
|
|
||||||
|
// disable copying
|
||||||
|
ANSIParser(ANSIParser& ap) = delete; |
||||||
|
|
||||||
|
bool parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb); |
||||||
|
}; |
@ -0,0 +1,163 @@ |
|||||||
|
#include <fmt/core.h> |
||||||
|
#include <string_view> |
||||||
|
#include "dbc.hpp" |
||||||
|
#include <SFML/Graphics.hpp> |
||||||
|
#include "ansi_parser.hpp" |
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
using namespace fmt; |
||||||
|
|
||||||
|
%%{ |
||||||
|
machine ansi_parser; |
||||||
|
alphtype int; |
||||||
|
|
||||||
|
action tstart { |
||||||
|
start = fpc; |
||||||
|
} |
||||||
|
|
||||||
|
action number { |
||||||
|
value = 0; |
||||||
|
size_t len = fpc - start; |
||||||
|
dbc::check(start[0] != '-', "negative numbers not supported"); |
||||||
|
|
||||||
|
switch(len) { |
||||||
|
case 10: value += (start[len-10] - '0') * 1000000000; [[fallthrough]]; |
||||||
|
case 9: value += (start[len- 9] - '0') * 100000000; [[fallthrough]]; |
||||||
|
case 8: value += (start[len- 8] - '0') * 10000000; [[fallthrough]]; |
||||||
|
case 7: value += (start[len- 7] - '0') * 1000000; [[fallthrough]]; |
||||||
|
case 6: value += (start[len- 6] - '0') * 100000; [[fallthrough]]; |
||||||
|
case 5: value += (start[len- 5] - '0') * 10000; [[fallthrough]]; |
||||||
|
case 4: value += (start[len- 4] - '0') * 1000; [[fallthrough]]; |
||||||
|
case 3: value += (start[len- 3] - '0') * 100; [[fallthrough]]; |
||||||
|
case 2: value += (start[len- 2] - '0') * 10; [[fallthrough]]; |
||||||
|
case 1: value += (start[len- 1] - '0'); |
||||||
|
break; |
||||||
|
default: |
||||||
|
dbc::sentinel("can't process > 10 digits"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
action color_out { |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
action is_fg { |
||||||
|
target = &color; |
||||||
|
} |
||||||
|
action is_bg { |
||||||
|
target = &bgcolor; |
||||||
|
} |
||||||
|
|
||||||
|
action out { |
||||||
|
write_cb(fc); |
||||||
|
} |
||||||
|
|
||||||
|
action reset_fg { |
||||||
|
color = $default_fg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
action reset_bg { |
||||||
|
bgcolor = $default_bg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
action invert { |
||||||
|
color = $default_bg; |
||||||
|
bgcolor = $default_fg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
action reset_invert { |
||||||
|
color = $default_fg; |
||||||
|
bgcolor = $default_bg; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
action half_bright { |
||||||
|
color = sf::Color(100,100,100); |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
action red_text { |
||||||
|
color = sf::Color::Red; |
||||||
|
color_cb(color, bgcolor); |
||||||
|
} |
||||||
|
|
||||||
|
action red { target->r = value; } |
||||||
|
action blue { target->g = value; } |
||||||
|
action green { target->b = value; } |
||||||
|
action start { value = 0; } |
||||||
|
action end {} |
||||||
|
action log { println("command {}", (char)fc); } |
||||||
|
|
||||||
|
ESC = 0x1B; |
||||||
|
start = ESC "["; |
||||||
|
fg = "38;" %is_fg; |
||||||
|
bg = "48;" %is_bg; |
||||||
|
reset = ("39" %reset_fg | "49" %reset_bg); |
||||||
|
num = digit+ >tstart %number; |
||||||
|
color256 = "5;"; |
||||||
|
color24b = "2;"; |
||||||
|
|
||||||
|
ansi = ( |
||||||
|
start %start |
||||||
|
( |
||||||
|
reset | |
||||||
|
"0" %reset_fg %reset_bg | |
||||||
|
"1" | |
||||||
|
"2" %half_bright | |
||||||
|
"3" | |
||||||
|
"4" | |
||||||
|
"5" | |
||||||
|
"6" | |
||||||
|
"7" %invert | |
||||||
|
"31" %red_text | |
||||||
|
"22" | |
||||||
|
"24" | |
||||||
|
"27" %reset_invert | |
||||||
|
"9" ["0"-"7"] | |
||||||
|
"10" ["0"-"7"] | |
||||||
|
(fg|bg) (color24b num %red ";" num %blue ";" num %green ) %color_out |
||||||
|
) "m" %end |
||||||
|
); |
||||||
|
|
||||||
|
other = (any+ @out -- ESC)*; |
||||||
|
|
||||||
|
main := (other :> ansi)**; |
||||||
|
}%% |
||||||
|
|
||||||
|
%% write data; |
||||||
|
|
||||||
|
#include <ftxui/screen/terminal.hpp> |
||||||
|
|
||||||
|
ANSIParser::ANSIParser(sf::Color default_fg, sf::Color default_bg) : |
||||||
|
$default_fg(default_fg), |
||||||
|
$default_bg(default_bg) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb) { |
||||||
|
const wchar_t *start = NULL; |
||||||
|
int cs = 0; |
||||||
|
unsigned int value = 0; |
||||||
|
const wchar_t *p = codes.data(); |
||||||
|
const wchar_t *pe = p + codes.size(); |
||||||
|
const wchar_t *eof = pe; |
||||||
|
sf::Color bgcolor($default_bg); |
||||||
|
sf::Color color($default_fg); |
||||||
|
sf::Color* target = &color; |
||||||
|
|
||||||
|
%% write init; |
||||||
|
%% write exec; |
||||||
|
|
||||||
|
bool good = pe - p == 0; |
||||||
|
|
||||||
|
if(!good) { |
||||||
|
p -= 10; |
||||||
|
// dear cthuhlu, save me from the pain that is wstring |
||||||
|
for(int i = 0; i < 100; i++) { |
||||||
|
try { |
||||||
|
print("{}", p[i] == 0x1B ? '^' : char(p[i])); |
||||||
|
} catch(...) { |
||||||
|
print("?=", int(p[i])); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return good; |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
namespace ColorValue { |
||||||
|
const sf::Color BLACK{1, 4, 2}; |
||||||
|
const sf::Color DARK_DARK{9, 29, 16}; |
||||||
|
const sf::Color DARK_MID{14, 50, 26}; |
||||||
|
const sf::Color DARK_LIGHT{0, 109, 44}; |
||||||
|
const sf::Color MID{63, 171, 92}; |
||||||
|
const sf::Color LIGHT_DARK{161, 217, 155}; |
||||||
|
const sf::Color LIGHT_MID{199, 233, 192}; |
||||||
|
const sf::Color LIGHT_LIGHT{229, 245, 224}; |
||||||
|
const sf::Color WHITE{255, 255, 255}; |
||||||
|
const sf::Color TRANSPARENT = sf::Color::Transparent; |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
#include "panel.hpp" |
||||||
|
#include "dbc.hpp" |
||||||
|
|
||||||
|
void Panel::resize(int w, int h) { |
||||||
|
$dirty = true; |
||||||
|
width = w; |
||||||
|
height = h; |
||||||
|
$screen = Screen(width, height); |
||||||
|
} |
||||||
|
|
||||||
|
void Panel::set_renderer(Component renderer) { |
||||||
|
$dirty = true; |
||||||
|
$component = renderer; |
||||||
|
} |
||||||
|
|
||||||
|
void Panel::add(Component child) { |
||||||
|
dbc::pre("must set_renderer first", $component != nullptr); |
||||||
|
$dirty = true; |
||||||
|
$component->Add(child); |
||||||
|
} |
||||||
|
|
||||||
|
void Panel::render() { |
||||||
|
$dirty = true; |
||||||
|
if(must_clear) $screen.Clear(); |
||||||
|
Render($screen, $component->Render()); |
||||||
|
} |
||||||
|
|
||||||
|
const std::wstring& Panel::to_string() { |
||||||
|
if($dirty) { |
||||||
|
std::string as_text = $screen.ToString(); |
||||||
|
$screenout = $converter.from_bytes(as_text); |
||||||
|
$dirty = false; |
||||||
|
} |
||||||
|
|
||||||
|
return $screenout; |
||||||
|
} |
||||||
|
|
||||||
|
void Panel::mouse_click(ftxui::Mouse::Button btn, Point pos) { |
||||||
|
ftxui::Mouse mev{ |
||||||
|
.button=btn, |
||||||
|
.motion=ftxui::Mouse::Motion::Pressed, |
||||||
|
.x=int(pos.x), .y=int(pos.y) |
||||||
|
}; |
||||||
|
|
||||||
|
$component->OnEvent(ftxui::Event::Mouse("", mev)); |
||||||
|
} |
||||||
|
|
||||||
|
void Panel::mouse_release(ftxui::Mouse::Button btn, Point pos) { |
||||||
|
ftxui::Mouse mev{ |
||||||
|
.button=btn, |
||||||
|
.motion=ftxui::Mouse::Motion::Released, |
||||||
|
.x=int(pos.x), .y=int(pos.y) |
||||||
|
}; |
||||||
|
|
||||||
|
$component->OnEvent(ftxui::Event::Mouse("", mev)); |
||||||
|
} |
||||||
|
|
||||||
|
const Screen& Panel::screen() { |
||||||
|
return $screen; |
||||||
|
} |
||||||
|
|
||||||
|
void Panel::key_press(ftxui::Event event) { |
||||||
|
$component->OnEvent(event); |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
#pragma once |
||||||
|
#include <ftxui/dom/node.hpp> // for Render |
||||||
|
#include <ftxui/component/component.hpp> |
||||||
|
#include <ftxui/component/mouse.hpp> |
||||||
|
#include <ftxui/dom/canvas.hpp> |
||||||
|
#include <ftxui/screen/screen.hpp> |
||||||
|
#include <ftxui/dom/canvas.hpp> |
||||||
|
#include <ftxui/screen/screen.hpp> |
||||||
|
#include <ftxui/dom/canvas.hpp> |
||||||
|
#include <SFML/Graphics/Color.hpp> |
||||||
|
#include <locale> |
||||||
|
#include <codecvt> |
||||||
|
#include "color.hpp" |
||||||
|
#include "point.hpp" |
||||||
|
|
||||||
|
const int UI_PANEL_BORDER_PX=5; |
||||||
|
|
||||||
|
using ftxui::Renderer, ftxui::Component, ftxui::Element, ftxui::Screen; |
||||||
|
|
||||||
|
class Panel { |
||||||
|
public: |
||||||
|
int x; |
||||||
|
int y; |
||||||
|
int width; |
||||||
|
int height; |
||||||
|
bool has_border = false; |
||||||
|
bool must_clear = true; |
||||||
|
bool grid = false; |
||||||
|
sf::Color default_bg = ColorValue::BLACK; |
||||||
|
sf::Color default_fg = ColorValue::LIGHT_LIGHT; |
||||||
|
sf::Color border_color = ColorValue::MID; |
||||||
|
int border_px = UI_PANEL_BORDER_PX; |
||||||
|
|
||||||
|
bool $dirty = true; |
||||||
|
Component $component = nullptr; |
||||||
|
Screen $screen; |
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter; |
||||||
|
std::wstring $screenout; |
||||||
|
|
||||||
|
Panel(int x, int y, int width, int height, bool is_grid=false) : |
||||||
|
x(x), |
||||||
|
y(y), |
||||||
|
width(width), |
||||||
|
height(height), |
||||||
|
grid(is_grid), |
||||||
|
$screen(Screen(width, height)) |
||||||
|
{ |
||||||
|
must_clear = !is_grid; |
||||||
|
}; |
||||||
|
|
||||||
|
void resize(int width, int height); |
||||||
|
void set_renderer(Component renderer); |
||||||
|
void add(Component child); |
||||||
|
void render(); |
||||||
|
void mouse_click(ftxui::Mouse::Button btn, Point pos); |
||||||
|
void mouse_release(ftxui::Mouse::Button btn, Point pos); |
||||||
|
void key_press(ftxui::Event event); |
||||||
|
const std::wstring &to_string(); |
||||||
|
const Screen &screen(); |
||||||
|
}; |
@ -0,0 +1,275 @@ |
|||||||
|
#include "render.hpp" |
||||||
|
#include "ansi_parser.hpp" |
||||||
|
#include <cmath> |
||||||
|
#include <fmt/core.h> |
||||||
|
#include <array> |
||||||
|
#include "map.hpp" |
||||||
|
#include <iostream> |
||||||
|
#include "color.hpp" |
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32) |
||||||
|
#include <stdio.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <io.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
using namespace fmt; |
||||||
|
|
||||||
|
SFMLRender::SFMLRender(sf::RenderWindow &window) : |
||||||
|
$window(window), |
||||||
|
$map_font_size(0), |
||||||
|
$line_spacing(0), |
||||||
|
$default_fg(ColorValue::LIGHT_MID), |
||||||
|
$default_bg(ColorValue::BLACK), |
||||||
|
$bg_sprite($font_texture), |
||||||
|
$font(FONT_FILE_NAME), |
||||||
|
$ui_text($font), |
||||||
|
$ansi($default_fg, $default_bg) |
||||||
|
{ |
||||||
|
// force true color, but maybe I want to support different color sets
|
||||||
|
$font.setSmooth(false); |
||||||
|
$ui_text.setPosition({0,0}); |
||||||
|
$ui_text.setCharacterSize($config.ui_font_size); |
||||||
|
$ui_text.setFillColor(ColorValue::LIGHT_MID); |
||||||
|
sf::Glyph glyph = $font.getGlyph($config.ui_base_char, $config.ui_font_size, false); |
||||||
|
$text_bounds = glyph.bounds; |
||||||
|
$cells_w = std::ceil($config.video_x / $text_bounds.size.x); |
||||||
|
$cells_h = std::ceil($config.video_y / $text_bounds.size.y); |
||||||
|
} |
||||||
|
|
||||||
|
sf::Sprite &SFMLRender::get_text_sprite(wchar_t tile) { |
||||||
|
if(!$sprites.contains(tile)) { |
||||||
|
sf::Glyph glyph = $font.getGlyph(tile, $map_font_size, false); |
||||||
|
// WARNING! we actually have to do this here because SFML caches
|
||||||
|
// the glyphs on the font texture, so this gets loaded each time
|
||||||
|
// we get a new glyph from the font.
|
||||||
|
$font_texture = $font.getTexture($map_font_size); |
||||||
|
$sprites.try_emplace(tile, $font_texture, glyph.textureRect); |
||||||
|
} |
||||||
|
|
||||||
|
return $sprites.at(tile); |
||||||
|
} |
||||||
|
|
||||||
|
void SFMLRender::clear_cache() { |
||||||
|
$sprites.clear(); |
||||||
|
bool good = $font.openFromFile(FONT_FILE_NAME); |
||||||
|
dbc::check(good, "Failed to load the font."); |
||||||
|
$font.setSmooth(false); |
||||||
|
$ui_text.setFont($font); |
||||||
|
} |
||||||
|
|
||||||
|
void SFMLRender::center_panel(Panel &panel) { |
||||||
|
int cell_center_x = ($cells_w - panel.width) / 2; |
||||||
|
int cell_center_y = ($cells_h - panel.height) / 2; |
||||||
|
|
||||||
|
panel.x = cell_center_x * $text_bounds.size.x; |
||||||
|
panel.y = cell_center_y * $text_bounds.size.y; |
||||||
|
} |
||||||
|
|
||||||
|
void SFMLRender::resize_grid(int new_size, Panel &panel_out) { |
||||||
|
auto glyph = $font.getGlyph($config.bg_tile, new_size, false); |
||||||
|
int view_x = std::ceil(($config.video_x - panel_out.x) / glyph.bounds.size.x); |
||||||
|
int view_y = std::ceil(($config.video_y - panel_out.y) / glyph.bounds.size.y); |
||||||
|
|
||||||
|
// looks good, set 'em all
|
||||||
|
$base_glyph = glyph; |
||||||
|
$map_font_size = new_size; |
||||||
|
$sprites.clear(); // need to reset the sprites for the new size
|
||||||
|
$line_spacing = $font.getLineSpacing($map_font_size); |
||||||
|
$bg_sprite = get_text_sprite($config.bg_tile); |
||||||
|
$grid_bounds = $bg_sprite.getLocalBounds(); |
||||||
|
panel_out.resize(view_x, view_y); |
||||||
|
} |
||||||
|
|
||||||
|
inline void configure_tile(const sf::Sprite &sprite, sf::FloatRect &sp_bounds, sf::FloatRect grid_bounds, float &width_delta, float &height_delta) { |
||||||
|
// BUG: I think I could create a struct that kept this info for all sprites loaded
|
||||||
|
// should look into caching all this instead of calcing it each time
|
||||||
|
sp_bounds = sprite.getLocalBounds(); |
||||||
|
|
||||||
|
// calculate where to center the sprite, but only if it's smaller
|
||||||
|
width_delta = grid_bounds.size.x > sp_bounds.size.x ? (grid_bounds.size.x - sp_bounds.size.x) / 2 : 0; |
||||||
|
height_delta = grid_bounds.size.y > sp_bounds.size.x ? (grid_bounds.size.y - sp_bounds.size.y) / 2 : 0; |
||||||
|
} |
||||||
|
|
||||||
|
void SFMLRender::render_grid(const std::wstring &text, sf::Color default_fg, sf::Color default_bg, float x, float y) { |
||||||
|
wchar_t last_tile = $config.bg_tile; |
||||||
|
sf::FloatRect sp_bounds; |
||||||
|
float width_delta = 0; |
||||||
|
float height_delta = 0; |
||||||
|
sf::Sprite &sprite = get_text_sprite(last_tile); |
||||||
|
const float start_x = x; |
||||||
|
sf::Color cur_fg = default_fg; |
||||||
|
sf::Color cur_bg = default_bg; |
||||||
|
|
||||||
|
$ansi.parse(text, [&](auto fg, auto bg) { |
||||||
|
cur_fg = fg; |
||||||
|
cur_bg = bg; |
||||||
|
}, |
||||||
|
|
||||||
|
[&](wchar_t tile) { |
||||||
|
switch(tile) { |
||||||
|
case '\r': break; // ignore it
|
||||||
|
case '\n': { |
||||||
|
// don't bother processing newlines, just skip
|
||||||
|
y += $line_spacing; |
||||||
|
x = start_x; |
||||||
|
} |
||||||
|
break; |
||||||
|
default: { |
||||||
|
// only get a new sprite if the tile changed
|
||||||
|
if(last_tile != tile) { |
||||||
|
sprite = get_text_sprite(tile); |
||||||
|
configure_tile(sprite, sp_bounds, $grid_bounds, width_delta, height_delta); |
||||||
|
last_tile = tile; // update last tile seen
|
||||||
|
} |
||||||
|
|
||||||
|
sprite.setPosition({x+width_delta, y+height_delta}); |
||||||
|
sprite.setColor(cur_fg); |
||||||
|
|
||||||
|
// only draw background char if it's different from default
|
||||||
|
if(cur_bg != default_bg) { |
||||||
|
$bg_sprite.setPosition({x, y}); |
||||||
|
$bg_sprite.setColor(cur_bg); |
||||||
|
$window.draw($bg_sprite); |
||||||
|
} |
||||||
|
|
||||||
|
$window.draw(sprite); |
||||||
|
// next cell
|
||||||
|
x += $base_glyph.advance; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
inline sf::FloatRect draw_chunk(sf::RenderWindow& window, |
||||||
|
sf::FloatRect text_bounds, sf::Text& text, sf::Color default_bg, |
||||||
|
sf::Color bgcolor, int bg_box_offset, float x, float y, std::wstring &out) |
||||||
|
{ |
||||||
|
text.setString(out); |
||||||
|
text.setPosition({x, y}); |
||||||
|
// get a base character for the cell size
|
||||||
|
sf::FloatRect bounds({x, y}, {text_bounds.size.x * out.size(), text_bounds.size.y}); |
||||||
|
|
||||||
|
if(default_bg != bgcolor) { |
||||||
|
sf::RectangleShape backing(bounds.size); |
||||||
|
backing.setFillColor(bgcolor); |
||||||
|
backing.setPosition({bounds.position.x, bounds.position.y + bg_box_offset}); |
||||||
|
window.draw(backing); |
||||||
|
} |
||||||
|
|
||||||
|
window.draw(text); |
||||||
|
out.clear(); |
||||||
|
return bounds; |
||||||
|
} |
||||||
|
|
||||||
|
void SFMLRender::render_text(const std::wstring &text, sf::Color default_fg, sf::Color default_bg, float start_x, float start_y) { |
||||||
|
std::wstring out; |
||||||
|
float x = start_x; |
||||||
|
float y = start_y; |
||||||
|
sf::Color cur_bg = default_bg; |
||||||
|
|
||||||
|
// start with the default_fg until it's changed
|
||||||
|
$ui_text.setFillColor(default_fg); |
||||||
|
|
||||||
|
$ansi.parse(text, |
||||||
|
[&](auto fg, auto bg) { |
||||||
|
if(out.size() > 0 ) { |
||||||
|
auto bounds = draw_chunk($window, |
||||||
|
$text_bounds, $ui_text, |
||||||
|
default_bg, cur_bg, $config.bg_box_offset, x, y, out); |
||||||
|
x += bounds.size.x; |
||||||
|
} |
||||||
|
cur_bg = bg; |
||||||
|
$ui_text.setFillColor(fg); |
||||||
|
}, |
||||||
|
[&](wchar_t tile) { |
||||||
|
switch(tile) { |
||||||
|
case '\r': break; // ignore it
|
||||||
|
case '\n': { |
||||||
|
sf::FloatRect bounds; |
||||||
|
|
||||||
|
if(out.size() > 0) { |
||||||
|
bounds = draw_chunk($window, $text_bounds, |
||||||
|
$ui_text, default_bg, cur_bg, $config.bg_box_offset, x, y, out); |
||||||
|
} else { |
||||||
|
bounds = $ui_text.getLocalBounds(); |
||||||
|
} |
||||||
|
|
||||||
|
y += bounds.size.y; |
||||||
|
x = start_x; // reset to the original position
|
||||||
|
} |
||||||
|
break; |
||||||
|
default: |
||||||
|
out += tile; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
if(out.size() > 0) { |
||||||
|
draw_chunk($window, $text_bounds, $ui_text, default_bg, cur_bg, $config.bg_box_offset, x, y, out); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void SFMLRender::draw_sprite(sf::Sprite &sprite, sf::Shader *shader) { |
||||||
|
$window.draw(sprite, shader); |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Does not render the panel, you have to do that so you can control |
||||||
|
* when things render. |
||||||
|
*/ |
||||||
|
void SFMLRender::draw(Panel &panel, float x_offset, float y_offset) { |
||||||
|
const std::wstring &panelout = panel.to_string(); |
||||||
|
|
||||||
|
auto bounds = panel.grid ? $grid_bounds : $text_bounds; |
||||||
|
|
||||||
|
sf::RectangleShape backing( |
||||||
|
sf::Vector2f(bounds.size.x * panel.width + panel.border_px, |
||||||
|
bounds.size.y * panel.height + panel.border_px)); |
||||||
|
|
||||||
|
backing.setFillColor(panel.default_bg); |
||||||
|
|
||||||
|
if(panel.has_border) { |
||||||
|
backing.setOutlineColor(panel.border_color); |
||||||
|
backing.setOutlineThickness(panel.border_px); |
||||||
|
} |
||||||
|
|
||||||
|
backing.setPosition({panel.x + x_offset, panel.y + y_offset}); |
||||||
|
$window.draw(backing); |
||||||
|
|
||||||
|
if(panel.grid) { |
||||||
|
render_grid(panelout, panel.default_fg, panel.default_bg, panel.x + x_offset, panel.y + y_offset); |
||||||
|
} else { |
||||||
|
render_text(panelout, panel.default_fg, panel.default_bg, panel.x + x_offset, panel.y + y_offset); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool SFMLRender::mouse_position(Panel &panel, Point &out) { |
||||||
|
// yes, you have to do this in sfml
|
||||||
|
sf::Vector2f pos = $window.mapPixelToCoords(sf::Mouse::getPosition($window)); |
||||||
|
|
||||||
|
auto bounds = panel.grid ? $grid_bounds : $text_bounds; |
||||||
|
|
||||||
|
if(pos.x >= panel.x && pos.y >= panel.y |
||||||
|
&& pos.x <= (panel.x + panel.width * bounds.size.x) |
||||||
|
&& pos.y <= (panel.y + panel.height * bounds.size.y)) |
||||||
|
{ |
||||||
|
out = { |
||||||
|
size_t((pos.x - panel.x) / bounds.size.x), |
||||||
|
size_t((pos.y - panel.y) / bounds.size.y) |
||||||
|
}; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void SFMLRender::init_terminal() { |
||||||
|
#if defined(_WIN64) || defined(_WIN32) |
||||||
|
_setmode(_fileno(stdout), _O_U16TEXT); |
||||||
|
#endif |
||||||
|
|
||||||
|
ftxui::Terminal::SetColorSupport(ftxui::Terminal::Color::TrueColor); |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <ftxui/screen/screen.hpp> |
||||||
|
#include <ftxui/dom/canvas.hpp> |
||||||
|
#include <SFML/Window.hpp> |
||||||
|
#include <SFML/System.hpp> |
||||||
|
#include <SFML/Graphics.hpp> |
||||||
|
#include <SFML/Graphics/Rect.hpp> |
||||||
|
#include "point.hpp" |
||||||
|
#include <codecvt> |
||||||
|
#include "ansi_parser.hpp" |
||||||
|
#include "panel.hpp" |
||||||
|
#include "constants.hpp" |
||||||
|
#include <optional> |
||||||
|
|
||||||
|
using ftxui::Canvas, ftxui::Screen; |
||||||
|
|
||||||
|
/*
|
||||||
|
* BUG: This could be so much better. |
||||||
|
*/ |
||||||
|
struct RenderConfig { |
||||||
|
unsigned int video_x = VIDEO_WINDOW_X; |
||||||
|
unsigned int video_y = VIDEO_WINDOW_Y; |
||||||
|
int ui_font_size=UI_FONT_SIZE; |
||||||
|
int base_map_font_size=BASE_MAP_FONT_SIZE; |
||||||
|
wchar_t bg_tile = BG_TILE; |
||||||
|
wchar_t ui_base_char = UI_BASE_CHAR; |
||||||
|
int bg_box_offset=BG_BOX_OFFSET; |
||||||
|
}; |
||||||
|
|
||||||
|
struct SFMLRender { |
||||||
|
int $cells_w = 0; |
||||||
|
int $cells_h = 0; |
||||||
|
RenderConfig $config; |
||||||
|
sf::RenderWindow& $window; |
||||||
|
int $map_font_size; |
||||||
|
float $line_spacing; |
||||||
|
sf::Color $default_fg; |
||||||
|
sf::Color $default_bg; |
||||||
|
sf::Texture $font_texture; |
||||||
|
sf::Sprite $bg_sprite; |
||||||
|
sf::Font $font; |
||||||
|
sf::Text $ui_text; |
||||||
|
ANSIParser $ansi; |
||||||
|
|
||||||
|
std::unordered_map<wchar_t, sf::Sprite> $sprites; |
||||||
|
sf::Glyph $base_glyph; |
||||||
|
sf::FloatRect $grid_bounds; |
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter; |
||||||
|
sf::FloatRect $text_bounds; |
||||||
|
|
||||||
|
SFMLRender(sf::RenderWindow& window); |
||||||
|
|
||||||
|
// disable copy
|
||||||
|
SFMLRender(SFMLRender &other) = delete; |
||||||
|
|
||||||
|
sf::Sprite &get_text_sprite(wchar_t tile); |
||||||
|
void resize_grid(int new_size, Panel &panel_out); |
||||||
|
void render_grid(const std::wstring &text, sf::Color default_fg, sf::Color default_bg, float x, float y); |
||||||
|
void render_text(const std::wstring &text, sf::Color default_fg, sf::Color default_bg, float x, float y); |
||||||
|
|
||||||
|
void draw(Panel &panel, float x_offset=0.0f, float y_offset=0.0f); |
||||||
|
void draw_sprite(sf::Sprite &sprite, sf::Shader *shader); |
||||||
|
void center_panel(Panel &panel); |
||||||
|
|
||||||
|
std::optional<sf::Event> poll_event() { |
||||||
|
return $window.pollEvent(); |
||||||
|
} |
||||||
|
|
||||||
|
void close() { return $window.close(); } |
||||||
|
|
||||||
|
bool is_open() { return $window.isOpen(); } |
||||||
|
|
||||||
|
int font_size() { return $map_font_size; } |
||||||
|
void clear() { $window.clear(); } |
||||||
|
void display() { $window.display(); } |
||||||
|
bool mouse_position(Panel &panel, Point &out); |
||||||
|
void clear_cache(); |
||||||
|
static void init_terminal(); |
||||||
|
}; |
@ -0,0 +1,15 @@ |
|||||||
|
[wrap-file] |
||||||
|
directory = FTXUI-5.0.0 |
||||||
|
source_url = https://github.com/ArthurSonzogni/FTXUI/archive/refs/tags/v5.0.0.tar.gz |
||||||
|
source_filename = FTXUI-5.0.0.tar.gz |
||||||
|
source_hash = a2991cb222c944aee14397965d9f6b050245da849d8c5da7c72d112de2786b5b |
||||||
|
patch_filename = ftxui_5.0.0-1_patch.zip |
||||||
|
patch_url = https://wrapdb.mesonbuild.com/v2/ftxui_5.0.0-1/get_patch |
||||||
|
patch_hash = 21c654e82739b90b95bd98c1d321264608d37c50d29fbcc3487f790fd5412909 |
||||||
|
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/ftxui_5.0.0-1/FTXUI-5.0.0.tar.gz |
||||||
|
wrapdb_version = 5.0.0-1 |
||||||
|
|
||||||
|
[provide] |
||||||
|
ftxui-screen = screen_dep |
||||||
|
ftxui-dom = dom_dep |
||||||
|
ftxui-component = component_dep |
Loading…
Reference in new issue