From 565ce754b0840da17ff0dd2062fccb77ed912a55 Mon Sep 17 00:00:00 2001 From: Adam Saponara Date: Sat, 30 Mar 2024 22:35:17 -0400 Subject: [PATCH] add `tb_get_cell` --- termbox2.h | 24 ++++++++++++++++++ tests/test_set_get/expected.ansi | 24 ++++++++++++++++++ tests/test_set_get/test.php | 43 ++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 tests/test_set_get/expected.ansi create mode 100755 tests/test_set_get/test.php diff --git a/termbox2.h b/termbox2.h index 4864940..b6cdfa3 100644 --- a/termbox2.h +++ b/termbox2.h @@ -499,6 +499,21 @@ int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg, uintattr_t bg); int tb_extend_cell(int x, int y, uint32_t ch); +/* Get cell at specified position. + * + * If position is valid, function returns TB_OK and cell contents are copied to + * `cell`. Note if `nech>0`, then `ech` will be a pointer to memory which may + * be invalid or freed after subsequent library calls. Callers must copy this + * memory if they need to persist it for some reason. Modifying memory at `ech` + * results in undefined behavior. + * + * If `back` is non-zero, return cells from the internal back buffer. Otherwise, + * return cells from the front buffer. Note the front buffer is updated on each + * call to tb_present(), whereas the back buffer is updated immediately by + * tb_set_cell() and other functions that mutate cell contents. + */ +int tb_get_cell(int x, int y, int back, struct tb_cell *cell); + /* Sets the input mode. Termbox has two input modes: * * 1. TB_INPUT_ESC @@ -1727,6 +1742,15 @@ int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg, return TB_OK; } +int tb_get_cell(int x, int y, int back, struct tb_cell *cell) { + if_not_init_return(); + int rv; + struct tb_cell *cellp = NULL; + rv = cellbuf_get(back ? &global.back : &global.front, x, y, &cellp); + if (cellp) memcpy(cell, cellp, sizeof(*cell)); + return rv; +} + int tb_extend_cell(int x, int y, uint32_t ch) { if_not_init_return(); #ifdef TB_OPT_EGC diff --git a/tests/test_set_get/expected.ansi b/tests/test_set_get/expected.ansi new file mode 100644 index 0000000..72715bc --- /dev/null +++ b/tests/test_set_get/expected.ansi @@ -0,0 +1,24 @@ +#5a +#5set=0 +#5invalid_get=-9 +#5back_get=0 +#5back_ch=a +#5back_fg=3 +#5back_bg=0 +#5front1_get=0 +#5front1_ch= +#5front1_fg=0 +#5front1_bg=0 +#5present=0 +#5front2_get=0 +#5front2_ch=a +#5front2_fg=3 +#5front2_bg=0 + + + + + + + + diff --git a/tests/test_set_get/test.php b/tests/test_set_get/test.php new file mode 100755 index 0000000..421acaf --- /dev/null +++ b/tests/test_set_get/test.php @@ -0,0 +1,43 @@ +ffi->tb_init(); + +$w = $test->ffi->tb_width(); +$h = $test->ffi->tb_height(); +$green = $test->defines['TB_GREEN']; +$cell = $test->ffi->new('struct tb_cell'); +$back = 1; +$front = 0; + +$result = []; + +$cell->ch = 42; + +$result['set'] = $test->ffi->tb_set_cell(0, 0, ord('a'), $green, 0); // 0 (TB_OK) + +$result['invalid_get'] = $test->ffi->tb_get_cell(-1, -1, $back, FFI::addr($cell)); // -9 (TB_ERR_OUT_OF_BOUNDS) + +$result['back_get'] = $test->ffi->tb_get_cell(0, 0, $back, FFI::addr($cell)); // 0 (TB_OK) +$result['back_ch'] = chr($cell->ch); // 'a' +$result['back_fg'] = $cell->fg; // 3 (green) +$result['back_bg'] = $cell->bg; // 0 + +$result['front1_get'] = $test->ffi->tb_get_cell(0, 0, $front, FFI::addr($cell)); +$result['front1_ch'] = chr($cell->ch); // (front buffer empty) +$result['front1_fg'] = $cell->fg; // 0 +$result['front1_bg'] = $cell->bg; // 0 + +$result['present'] = $test->ffi->tb_present(); // 0 (TB_OK) (front buffer now populated) + +$result['front2_get'] = $test->ffi->tb_get_cell(0, 0, $front, FFI::addr($cell)); // 0 (TB_OK) +$result['front2_ch'] = chr($cell->ch); // 'a' +$result['front2_fg'] = $cell->fg; // 3 (green) +$result['front2_bg'] = $cell->bg; // 0 + +$y = 1; +foreach ($result as $k => $v) $test->ffi->tb_printf(0, $y++, 0, 0, '%s=%s', $k, "$v"); + +$test->ffi->tb_present(); + +$test->screencap();