display

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

commitc3562086eae3af96eb7920d1da1d16a44cfa6cce
parentb8053e4af8e8d4ffce5a834a423bbc16c80ae12f
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateSat, 8 Feb 2025 16:29:35 +0100

Make sure there are no overflows beyond the screen

Diffstat:
MCMakeLists.txt|+-
Mexample/example.cpp|+++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Ainclude/display/utility.hpp|++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

3 files changed, 110 insertions(+), 29 deletions(-)


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

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

project(
display
VERSION 0.1.7
VERSION 0.1.8
DESCRIPTION "TUI library"
HOMEPAGE_URL "https://example.com/"
LANGUAGES CXX

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

@@ -4,48 +4,67 @@

#include "alec/alec.hpp"
#include "display/display.hpp"
#include "display/layout.hpp"
#include "display/utility.hpp"
namespace
{
int renderer(display::Window& win)
{
using display::add_lim, display::sub_lim;
using display::PvtX, display::PvtY;
using display::sz_t;
static int color_red = 0;
display::sz_t start_x = 0;
display::sz_t end_x = 0;
display::sz_t start_y = 0;
display::sz_t end_y = 0;
sz_t start_x = 0;
sz_t end_x = 0;
sz_t start_y = 0;
sz_t end_y = 0;
const auto [cols, rows] = alec::get_screen_size();
const auto [posx, posy, _] = win.pos();
const auto [wdth, hght] = win.dim();
const display::sz_t zero = 0;
const sz_t wdthm = wdth / 2;
const sz_t hghtm = hght / 2;
// Skip when pivot is outside the boundary
if (posx < 0 || posx > cols) {
return 0;
}
if (posy < 0 || posy > rows) {
return 0;
}
switch (win.piv().x) {
case PvtX::Left:
start_x = win.pos().x;
end_x = start_x + win.dim().width;
start_x = posx;
end_x = add_lim(start_x, wdth, cols);
break;
case PvtX::Center:
start_x = win.pos().x - win.dim().width / 2;
end_x = start_x + win.dim().width;
start_x = sub_lim(posx, wdthm, zero);
end_x = add_lim(posx, wdthm, cols);
break;
case PvtX::Right:
end_x = win.pos().x;
start_x = end_x - win.dim().width;
end_x = posx;
start_x = sub_lim(end_x, wdth, zero);
break;
}
switch (win.piv().y) {
case PvtY::Top:
start_y = win.pos().y;
end_y = start_y + win.dim().height;
start_y = posy;
end_y = add_lim(start_y, hght, rows);
break;
case PvtY::Center:
start_y = win.pos().y - win.dim().height / 2;
end_y = start_y + win.dim().height;
start_y = sub_lim(posy, hghtm, zero);
end_y = add_lim(posy, hghtm, rows);
break;
case PvtY::Bottom:
end_y = win.pos().y;
start_y = end_y - win.dim().height;
end_y = posy;
start_y = sub_lim(end_y, hght, zero);
break;
}

@@ -53,7 +72,7 @@ int renderer(display::Window& win)

std::cout << alec::background(color_red, 65, 65);
for (auto ypos = start_y; ypos <= end_y; ypos++) {
std::cout << alec::cursor_position(ypos, start_x);
std::cout << std::string(win.dim().width, ' ');
std::cout << std::string(end_x - start_x + 1, ' ');
}
std::cout << alec::background_v<alec::Color::DEFAULT>;
std::cout << std::flush;

@@ -71,17 +90,17 @@ int main()

auto redraw = [&]()
{
const auto [cols, rows] = alec::get_screen_size();
const std::uint16_t colsm = cols / 2;
const std::uint16_t rowm = rows / 2;
layout[0].pos() = {0, 0};
layout[1].pos() = {colsm, 0};
layout[2].pos() = {cols, 0};
layout[3].pos() = {cols, rowm};
layout[4].pos() = {cols, rows};
layout[5].pos() = {colsm, rows};
layout[6].pos() = {0, rows};
layout[7].pos() = {0, rowm};
const display::sz_t colsm = cols / 2;
const display::sz_t rowm = rows / 2;
layout[4].pos() = {0, 0};
layout[5].pos() = {colsm, 0};
layout[6].pos() = {cols, 0};
layout[7].pos() = {cols, rowm};
layout[0].pos() = {cols, rows};
layout[1].pos() = {colsm, rows};
layout[2].pos() = {0, rows};
layout[3].pos() = {0, rowm};
layout[8].pos() = {colsm, rowm};
layout.render(renderer);

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

@@ -0,0 +1,62 @@

#pragma once
#include <algorithm>
namespace display
{
template<typename T>
inline bool is_oveflow_lim(T val, T add, T lim)
{
return val > lim || add > lim || val > lim - add;
}
template<typename T>
inline bool is_underflow_lim(T val, T sub, T lim)
{
return val < lim || sub < lim || val < lim + sub;
}
template<typename T>
inline bool is_oveflow(T val, T add)
{
return val > std::numeric_limits<T>::max() - add;
}
template<typename T>
inline bool is_underflow(T val, T sub)
{
return val < std::numeric_limits<T>::min() + sub;
}
template<typename T>
inline T add_lim(T val, T add, T lim)
{
return !is_oveflow_lim(val, add, lim) ? val + add : lim;
}
template<typename T>
inline T sub_lim(T val, T sub, T lim)
{
return !is_underflow_lim(val, sub, lim) ? val - sub : lim;
}
template<typename T>
inline T clamp_low(T val, T low)
{
return std::max(val, low);
}
template<typename T>
inline T clamp_high(T val, T high)
{
return std::min(val, high);
}
template<typename T>
inline T clamp(T val, T low, T high)
{
return std::max(std::min(val, high), low);
}
} // namespace display