display

Layout and Rendering TUI library
git clone git://git.dimitrijedobrota.com/display.git
Log | Files | Refs | README | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |

commit714563ba3fb520f00631d52a401213ddd47e887b
parent89e5b7529d229b077ff679fef4d702996a09b7a1
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateThu, 20 Feb 2025 19:39:09 +0100

Proper, 4-way, corners for LayoutRigidBorder

Diffstat:
MCMakeLists.txt|+-
Mexample/example.cpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Minclude/display/layout_rigid.hpp|+++++++++++++-----------

3 files changed, 75 insertions(+), 20 deletions(-)


diff --git a/CMakeLists.txt b/CMakeLists.txt

@@ -4,7 +4,7 @@ include(cmake/prelude.cmake)

project(
display
VERSION 0.1.35
VERSION 0.1.36
DESCRIPTION "TUI library"
HOMEPAGE_URL "git://git.dimitrijedobrota.com/display.git"
LANGUAGES CXX

diff --git a/example/example.cpp b/example/example.cpp

@@ -57,9 +57,33 @@ public:

class LayoutRigidBorder : public LayoutRigid<LayoutCustom>
{
public:
LayoutRigidBorder(place_t aplc, layout_t layout)
: LayoutRigid<LayoutCustom>(aplc, std::move(layout))
LayoutRigidBorder(place_t aplc, const layout_t& layout)
: LayoutRigid<LayoutCustom>(aplc, layout)
{
auto [m, n] = get_grid();
const auto valid = [&](std::size_t xpos, std::size_t ypos)
{ return xpos >= 0 && xpos < n && ypos >= 0 && ypos < m; };
const auto get = [&](std::size_t xpos, std::size_t ypos) -> std::uint8_t
{ return valid(xpos, ypos) ? layout[xpos][ypos] : 0xFF; };
for (std::size_t i = 0; i <= n; i++) {
for (std::size_t j = 0; j <= m; j++) {
const std::uint8_t ptl = get(i - 1, j - 1);
const std::uint8_t ptr = get(i - 1, j);
const std::uint8_t pbl = get(i, j - 1);
const std::uint8_t pbr = get(i, j);
uint8_t mask = 0;
mask |= ((ptl != ptr) ? 1U : 0U) << 0U; // Top
mask |= ((ptr != pbr) ? 1U : 0U) << 1U; // Right
mask |= ((pbr != pbl) ? 1U : 0U) << 2U; // Bottom
mask |= ((pbl != ptl) ? 1U : 0U) << 3U; // Left
m_corners.emplace_back(mask, i, j);
}
}
}
template<class... Args>

@@ -84,13 +108,11 @@ public:

for (std::size_t i = 0; i < size(); i++) {
const auto [pos, dim] = LayoutRigid<LayoutCustom>::place(i);
set_cursor(pos.y, pos.x);
set_cursor(pos.y, pos.x + 1);
std::cout << "┌";
for (sz_t j = 1; j < dim.width; j++) {
std::cout << "─";
}
std::cout << "┐";
for (sz_t j = pos.y + 1; j < pos.y + dim.height; j++) {
set_cursor(j, pos.x) << "│";

@@ -101,12 +123,20 @@ public:

set_cursor(i, axpos() + awth() - 1) << "│";
}
set_cursor(aypos() + ahgt() - 1, axpos());
std::cout << "└";
set_cursor(aypos() + ahgt() - 1, axpos() + 1);
for (sz_t i = 2; i < awth(); i++) {
std::cout << "─";
}
std::cout << "┘";
auto [m, n] = get_grid();
const auto [w, h] = adim();
const sz_t unw = w / m;
const sz_t unh = h / n;
for (const auto [mask, xpos, ypos] : m_corners) {
const sz_t xloc = xpos != n ? xpos * unw : axpos() + w;
const sz_t yloc = ypos != m ? ypos * unh : aypos() + h;
set_cursor(yloc, xloc) << corner_t::lookup[mask]; // NOLINT
};
std::cout << std::flush;
}

@@ -127,6 +157,29 @@ private:

return {pos + pos_t(1, 1), dim - sub};
}
struct corner_t
{
// clang-format off
constexpr static const char* lookup[] = { // NOLINT
"", "", "", "└", "", "│", "┌", "├",
"", "┘", "─", "┴", "┐", "┤", "┬", "┼"
};
// clang-format on
corner_t(std::uint8_t mask, sz_t ypos, sz_t xpos) // NOLINT
: mask(mask)
, x(xpos)
, y(ypos)
{
}
std::uint8_t mask;
sz_t x;
sz_t y;
};
std::vector<corner_t> m_corners;
};
} // namespace

diff --git a/include/display/layout_rigid.hpp b/include/display/layout_rigid.hpp

@@ -58,7 +58,8 @@ protected:

return {this->apos() + start, dim};
}
const auto& get_record(std::size_t idx) { return m_recs[idx]; }
const auto& get_record(std::size_t idx) const { return m_recs[idx]; }
auto get_grid() const { return m_grid; }
struct record_t
{

@@ -82,8 +83,7 @@ LayoutRigid<T>::LayoutRigid(place_t aplc, layout_t layout)

static_cast<sz_t>(layout.size()))
, m_recs(count_and_pad(layout))
{
static const auto& insert =
[](sz_t& count, std::uint8_t cnt, sz_t& pos, std::uint8_t total)
static const auto& insert = [](sz_t& count, sz_t cnt, sz_t& pos, sz_t total)
{
if (count != 0 && (pos != total || count != cnt)) {
throw std::runtime_error("Invalid layout [Shape]");

@@ -97,11 +97,13 @@ LayoutRigid<T>::LayoutRigid(place_t aplc, layout_t layout)

count = cnt;
};
for (std::size_t i = 0U; i < m_grid.height; i++) {
uint8_t cnt = 1;
static const sz_t one = 1;
for (sz_t i = 0U; i < m_grid.height; i++) {
sz_t cnt = 1;
m_recs[layout[i][m_grid.width - 1]].addw = true;
for (std::size_t j = 0U; j < m_grid.width; j++) {
for (sz_t j = 0U; j < m_grid.width; j++) {
const auto crnt = layout[i][j];
if (crnt == layout[i][j + 1]) {

@@ -109,16 +111,16 @@ LayoutRigid<T>::LayoutRigid(place_t aplc, layout_t layout)

continue;
}
insert(m_recs[crnt].dim.width, cnt, m_recs[crnt].start.x, j - cnt + 1);
insert(m_recs[crnt].dim.width, cnt, m_recs[crnt].start.x, j - cnt + one);
cnt = 1;
}
}
for (std::size_t j = 0U; j < m_grid.width; j++) {
uint8_t cnt = 1;
for (sz_t j = 0U; j < m_grid.width; j++) {
sz_t cnt = 1;
m_recs[layout[m_grid.height - 1][j]].addh = true;
for (std::size_t i = 0U; i < m_grid.height; i++) {
for (sz_t i = 0U; i < m_grid.height; i++) {
const auto crnt = layout[i][j];
if (crnt == layout[i + 1][j]) {

@@ -126,7 +128,7 @@ LayoutRigid<T>::LayoutRigid(place_t aplc, layout_t layout)

continue;
}
insert(m_recs[crnt].dim.height, cnt, m_recs[crnt].start.y, i - cnt + 1);
insert(m_recs[crnt].dim.height, cnt, m_recs[crnt].start.y, i - cnt + one);
cnt = 1;
}
}