2020-06-08 07:01:58 +00:00
# include "main.h"
# include "internal.h"
TEST_CASE ( " TextLayout " ) {
2020-06-16 03:58:43 +00:00
auto nc_ = testing_notcurses ( ) ;
2020-06-08 07:01:58 +00:00
if ( ! nc_ ) {
return ;
}
ncplane * ncp_ = notcurses_stdplane ( nc_ ) ;
REQUIRE ( ncp_ ) ;
const char str [ ] = " this is going to be broken up " ;
SUBCASE ( " LayoutLeft " ) {
auto sp = ncplane_new ( nc_ , 2 , 20 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , str , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( str ) ) ;
2020-06-16 06:12:11 +00:00
char * line = ncplane_contents ( sp , 0 , 0 , 2 , 20 ) ;
2020-06-16 03:58:43 +00:00
REQUIRE ( line ) ;
2020-07-24 01:14:34 +00:00
CHECK ( 0 = = strcmp ( line , " this is going to be broken up " ) ) ;
2020-06-16 03:58:43 +00:00
free ( line ) ;
2020-06-08 07:01:58 +00:00
ncplane_destroy ( sp ) ;
}
SUBCASE ( " LayoutRight " ) {
auto sp = ncplane_new ( nc_ , 2 , 20 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_RIGHT , str , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( str ) ) ;
2020-06-16 06:12:11 +00:00
char * line = ncplane_contents ( sp , 0 , 0 , 2 , 20 ) ;
2020-06-16 04:30:02 +00:00
REQUIRE ( line ) ;
2020-07-24 01:14:34 +00:00
CHECK ( 0 = = strcmp ( line , " this is going to be broken up " ) ) ;
2020-06-16 04:30:02 +00:00
free ( line ) ;
2020-06-08 07:01:58 +00:00
ncplane_destroy ( sp ) ;
}
SUBCASE ( " LayoutCenter " ) {
auto sp = ncplane_new ( nc_ , 2 , 20 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_CENTER , str , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( str ) ) ;
2020-06-16 06:12:11 +00:00
char * line = ncplane_contents ( sp , 0 , 0 , 2 , 20 ) ;
2020-06-16 04:30:02 +00:00
REQUIRE ( line ) ;
2020-07-24 01:14:34 +00:00
CHECK ( 0 = = strcmp ( line , " this is going to be broken up " ) ) ;
2020-06-16 04:30:02 +00:00
free ( line ) ;
2020-06-08 07:01:58 +00:00
ncplane_destroy ( sp ) ;
}
2020-06-16 05:08:48 +00:00
// lay out text where a word ends on the boundary
SUBCASE ( " LayoutOnBoundary " ) {
auto sp = ncplane_new ( nc_ , 2 , 10 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " my nuclear arms " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_CENTER , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
2020-06-16 06:12:11 +00:00
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
2020-06-16 05:08:48 +00:00
REQUIRE ( line ) ;
2020-06-16 06:12:11 +00:00
CHECK ( 0 = = strcmp ( line , " my nucleararms " ) ) ;
2020-06-16 05:08:48 +00:00
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-06-16 05:22:40 +00:00
// lay out text where a word crosses the boundary
SUBCASE ( " LayoutCrossBoundary " ) {
auto sp = ncplane_new ( nc_ , 3 , 10 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " my grasping arms " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_CENTER , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
2020-06-16 06:12:11 +00:00
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
2020-06-16 05:22:40 +00:00
REQUIRE ( line ) ;
2020-06-16 06:12:11 +00:00
CHECK ( 0 = = strcmp ( line , " mygraspingarms " ) ) ;
2020-06-16 05:22:40 +00:00
free ( line ) ;
2020-06-16 06:12:11 +00:00
ncplane_destroy ( sp ) ;
}
2020-07-23 07:19:35 +00:00
// lay out text where a wide word crosses the boundary
SUBCASE ( " LayoutCrossBoundaryWide " ) {
2020-07-27 03:00:16 +00:00
if ( enforce_utf8 ( ) ) {
auto sp = ncplane_new ( nc_ , 2 , 6 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " a 血的神 " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_CENTER , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " a血的神 " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-07-23 07:19:35 +00:00
}
2020-07-22 06:08:30 +00:00
// a long word (one requiring a split no matter what) ought not force the
// next line, but instead be printed where it starts
2020-06-16 06:42:08 +00:00
SUBCASE ( " LayoutTransPlanar " ) {
2020-06-16 06:12:11 +00:00
auto sp = ncplane_new ( nc_ , 3 , 10 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " my thermonuclear arms " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_CENTER , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
2020-06-16 05:22:40 +00:00
REQUIRE ( line ) ;
2020-07-22 06:08:30 +00:00
CHECK ( 0 = = strcmp ( line , " my thermonucleararms " ) ) ;
2020-06-16 06:42:08 +00:00
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-07-24 01:17:04 +00:00
// a long word (one requiring a split no matter what) ought not force the
// next line, but instead be printed where it starts
SUBCASE ( " LayoutTransPlanarWide " ) {
2020-07-27 03:00:16 +00:00
if ( enforce_utf8 ( ) ) {
auto sp = ncplane_new ( nc_ , 2 , 8 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " 1 我能吞下玻璃 " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_CENTER , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " 1 我能吞下玻璃 " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-07-24 01:17:04 +00:00
}
2020-06-16 06:42:08 +00:00
SUBCASE ( " LayoutLeadingSpaces " ) {
auto sp = ncplane_new ( nc_ , 3 , 10 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " \t \n my thermonuclear arms " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_CENTER , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
2020-07-22 06:08:30 +00:00
CHECK ( 0 = = strcmp ( line , " my thermonucleararms " ) ) ;
2020-06-16 05:22:40 +00:00
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-06-16 06:47:21 +00:00
// create a plane of a single row, and fill it exactly with one word
SUBCASE ( " LayoutFills1DPlane " ) {
auto sp = ncplane_new ( nc_ , 1 , 14 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " quarkgluonfart " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " quarkgluonfart " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
// create a plane of a single row, and fill it exactly with words
SUBCASE ( " LayoutFills1DPlaneWords " ) {
auto sp = ncplane_new ( nc_ , 1 , 16 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " quark gluon fart " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " quark gluon fart " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
// create a plane of two rows, and exactly fill the first line
SUBCASE ( " LayoutFillsSingleLine " ) {
auto sp = ncplane_new ( nc_ , 2 , 13 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " quantum balls " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " quantum balls " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
// create a plane of two rows, and exactly fill both
SUBCASE ( " LayoutFillsPlane " ) {
auto sp = ncplane_new ( nc_ , 2 , 13 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
2020-07-04 02:42:34 +00:00
const char boundstr [ ] = " quantum balls scratchy no?! " ;
2020-06-16 06:47:21 +00:00
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
2020-07-04 02:42:34 +00:00
CHECK ( 0 = = strcmp ( line , " quantum ballsscratchy no?! " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-07-23 04:29:50 +00:00
// create a plane of two rows, and exactly fill both, with no spaces
2020-07-23 04:17:29 +00:00
SUBCASE ( " LayoutFillsPlaneNoSpaces " ) {
auto sp = ncplane_new ( nc_ , 2 , 6 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " 0123456789AB " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " 0123456789AB " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
// create a plane of two rows, and exactly fill both with wide chars
SUBCASE ( " LayoutFillsPlaneWide " ) {
2020-07-27 03:00:16 +00:00
if ( enforce_utf8 ( ) ) {
auto sp = ncplane_new ( nc_ , 2 , 6 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " 我能吞 下玻璃 " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " 我能吞下玻璃 " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-07-23 04:17:29 +00:00
}
2020-07-04 02:42:34 +00:00
SUBCASE ( " LayoutLongNoScroll " ) {
auto sp = ncplane_new ( nc_ , 2 , 13 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
const char boundstr [ ] = " quantum balls scratchy no?! truly! arrrrp " ;
int res = ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ;
CHECK ( 0 > res ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes < strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
CHECK ( 0 = = strcmp ( line , " quantum ballsscratchy no?! " ) ) ;
free ( line ) ;
ncplane_destroy ( sp ) ;
}
SUBCASE ( " LayoutLongScroll " ) {
auto sp = ncplane_new ( nc_ , 2 , 13 , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
ncplane_set_scrolling ( sp , true ) ;
size_t bytes ;
const char boundstr [ ] = " quantum balls scratchy?! true! arrrrp " ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , boundstr , & bytes ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
CHECK ( bytes = = strlen ( boundstr ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
2020-07-04 02:46:08 +00:00
CHECK ( 0 = = strcmp ( line , " scratchy?!true! arrrrp " ) ) ;
2020-06-16 06:47:21 +00:00
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-08-12 06:43:52 +00:00
SUBCASE ( " LayoutLongLines " ) {
// straight from the zoo demo, which didn't work at first
const int READER_COLS = 71 ; // equal to longest line
const int READER_ROWS = 4 ;
const char text [ ] =
" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ornare "
" neque ac ipsum viverra, vestibulum hendrerit leo consequat. Integer "
" velit, pharetra sed nisl quis, porttitor ornare purus. Cras ac "
" sollicitudin dolor, eget elementum dolor. Quisque lobortis sagittis. " ;
auto sp = ncplane_new ( nc_ , READER_ROWS , READER_COLS , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
ncplane_home ( sp ) ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , text , & bytes ) ) ;
CHECK ( bytes = = strlen ( text ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
// FIXME check line
free ( line ) ;
ncplane_destroy ( sp ) ;
}
SUBCASE ( " LayoutZooText " ) {
// straight from the zoo demo, which didn't work at first
const int READER_COLS = 64 ;
const int READER_ROWS = 8 ;
const char text [ ] =
" Notcurses provides several widgets to quickly build vivid TUIs. \n \n "
" This NCReader widget facilitates free-form text entry complete with readline-style bindings. " " NCSelector allows a single option to be selected from a list. " " NCMultiselector allows 0..n options to be selected from a list of n items. "
" NCFdplane streams a file descriptor, while NCSubproc spawns a subprocess and streams its output. "
" A variety of plots are supported, and menus can be placed along the top and/or bottom of any plane. \n \n "
" Widgets can be controlled with the keyboard and/or mouse. They are implemented atop ncplanes, and these planes can be manipulated like all others. " ;
auto sp = ncplane_new ( nc_ , READER_ROWS , READER_COLS , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
ncplane_set_scrolling ( sp , true ) ;
size_t bytes ;
ncplane_home ( sp ) ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , text , & bytes ) ) ;
CHECK ( bytes = = strlen ( text ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
// FIXME check line
free ( line ) ;
ncplane_destroy ( sp ) ;
}
SUBCASE ( " LayoutZooTextNoScroll " ) {
// straight from the zoo demo, which didn't work at first
const int READER_COLS = 64 ;
const int READER_ROWS = 15 ;
const char text [ ] =
" Notcurses provides several widgets to quickly build vivid TUIs. \n \n "
" This NCReader widget facilitates free-form text entry complete with readline-style bindings. "
" NCSelector allows a single option to be selected from a list. "
" NCMultiselector allows 0..n options to be selected from a list of n items. "
" NCFdplane streams a file descriptor, while NCSubproc spawns a subprocess and streams its output. "
" A variety of plots are supported, and menus can be placed along the top and/or bottom of any plane. \n \n "
" Widgets can be controlled with the keyboard and/or mouse. They are implemented atop ncplanes, and these planes can be manipulated like all others. " ;
auto sp = ncplane_new ( nc_ , READER_ROWS , READER_COLS , 0 , 0 , nullptr ) ;
REQUIRE ( sp ) ;
size_t bytes ;
ncplane_home ( sp ) ;
CHECK ( 0 < ncplane_puttext ( sp , 0 , NCALIGN_LEFT , text , & bytes ) ) ;
CHECK ( bytes = = strlen ( text ) ) ;
CHECK ( 0 = = notcurses_render ( nc_ ) ) ;
char * line = ncplane_contents ( sp , 0 , 0 , - 1 , - 1 ) ;
REQUIRE ( line ) ;
// FIXME check line
free ( line ) ;
ncplane_destroy ( sp ) ;
}
2020-06-08 07:01:58 +00:00
CHECK ( 0 = = notcurses_stop ( nc_ ) ) ;
}