display

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

commit de1902c7b94dae6042963b6eee1bb79dd9a3f891
parent e6af90c90ead078a849819036ea5a91775caf259
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Wed, 19 Feb 2025 00:04:40 +0100

Great simplification by cutting out BS

* padd_t with all 4 directions
* No more WindowPadding and WindowTypes
* Every windows specifies it's own padding
* Window::render() draws it to screen
* Opionaly Window::render_border() draws a border around everything
* No need for WindowPivot to be a template

Diffstat:
M CMakeLists.txt | + --
M example/example.cpp | ++ --
M example/navig/navig.cpp | +++++ -----
M include/display/types.hpp | +++++++++++++++++++++++++++++++++++++
M include/display/window.hpp | +++++++++++++++++++ -----------
D include/display/window_padd.hpp | ----------------------------------------------------------------------------
M include/display/window_pivot.hpp | ++++++ -----------
M source/window.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++ -----
D source/window_padd.cpp | ------------------------------------------------------------------------
M source/window_pivot.cpp | +++ --

10 files changed, 122 insertions(+), 186 deletions(-)


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

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


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

@@ -21,7 +21,6 @@ add_library(

display_display
source/display.cpp
source/window.cpp
source/window_padd.cpp
source/window_pivot.cpp
)
target_link_libraries(display_display PUBLIC alec::alec)

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

@@ -12,11 +12,11 @@ namespace

using display::PvtX, display::PvtY;
using display::sz_t, display::dim_t, display::piv_t, display::place_t;

class WindowCustom : public display::WindowPivot<display::Window>
class WindowCustom : public display::WindowPivot
{
public:
explicit WindowCustom(place_t aplc, piv_t piv, dim_t dim)
: WindowPivot(aplc, piv, dim)
: WindowPivot(aplc, {0, 0}, piv, dim)
{
}

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

@@ -6,7 +6,6 @@


#include "display/display.hpp"
#include "display/layout.hpp"
#include "display/window_padd.hpp"
#include "display/window_pivot.hpp"
#include "menu.hpp"

@@ -15,15 +14,15 @@ namespace


bool is_finished = false; // NOLINT

using display::WindowPivot, display::WindowPadd, display::WindowType;
using display::WindowPivot;

class WindowCustom : public WindowPivot<WindowPadd<WindowType::BorderBox>>
class WindowCustom : public WindowPivot
{
public:
WindowCustom(display::place_t aplc,
display::piv_t piv,
const example::menu_t& menu)
: WindowPivot(aplc, piv, calc_dim(menu))
: WindowPivot(aplc, {4, 5, 2, 4}, piv, calc_dim(menu))
, m_menu(menu)
{
}

@@ -47,7 +46,8 @@ public:

}
}

WindowPadd<WindowType::BorderBox>::render();
WindowPivot::render();
Window::render_border();

std::cout << alec::background_v<alec::Color::DEFAULT>;
std::cout << std::flush;

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

@@ -12,6 +12,35 @@ using event = alec::event;


using sz_t = std::uint16_t;

struct padd_t
{
padd_t()
: padd_t(0, 0, 0, 0)
{
}

padd_t(sz_t width, sz_t height) // NOLINT
: padd_t(width, width, height, height)
{
}

padd_t(sz_t leftpos, sz_t rightpos, sz_t toppos, sz_t bottompos) // NOLINT
: left(leftpos)
, right(rightpos)
, top(toppos)
, bottom(bottompos)
{
}

sz_t width() const { return left + right; }
sz_t height() const { return top + bottom; }

sz_t left;
sz_t right;
sz_t top;
sz_t bottom;
};

struct dim_t
{
dim_t()

@@ -39,6 +68,14 @@ struct dim_t

};
}

dim_t operator+(padd_t rhs) const
{
return {
static_cast<sz_t>(width + rhs.width()),
static_cast<sz_t>(height + rhs.height()),
};
}

sz_t width;
sz_t height;
};

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

@@ -5,23 +5,23 @@


namespace display
{

class Window : public Element
{
public:
using ustring = std::basic_string<unsigned char>;

explicit Window(place_t aplc, dim_t padding = {0, 0})
explicit Window(place_t aplc, padd_t padd)
: Element(aplc)
, m_padding(padding)
, m_padd(padd)
{
}

void render() const override;
void clear() const override;
void input(event& /* unused */) override {}

void render_border() const;

protected:
static dim_t padding() { return {0, 0}; }
padd_t padd() const { return m_padd; }

static std::ostream& set_cursor(sz_t posy, sz_t posx);
std::ostream& line_next() const;

@@ -35,13 +35,21 @@ protected:

place_t plc() const { return {pos(), dim()}; }
pos_t pos() const { return {xpos(), ypos()}; }
dim_t dim() const { return {wth(), hgt()}; }
sz_t xpos() const { return axpos() + (m_padding.width / 2); }
sz_t ypos() const { return aypos() + (m_padding.height / 2); }
sz_t wth() const { return awth() - m_padding.width; }
sz_t hgt() const { return ahgt() - m_padding.height; }
sz_t xpos() const { return axpos() + m_padd.left; }
sz_t ypos() const { return aypos() + m_padd.top; }
sz_t wth() const { return awth() - m_padd.width(); }
sz_t hgt() const { return ahgt() - m_padd.height(); }

private:
dim_t m_padding;
using Element::adim;
using Element::ahgt;
using Element::aplc;
using Element::apos;
using Element::awth;
using Element::axpos;
using Element::aypos;

padd_t m_padd;

mutable display::sz_t m_ypos = 0;
};

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

@@ -1,76 +0,0 @@

#pragma once

#include "display/window.hpp"

namespace display
{

enum class WindowType : std::uint8_t
{
Bare,
Border,
Box,
BorderBox,
};

template<WindowType T>
class WindowPadd : public Window
{
public:
explicit WindowPadd(place_t aplc)
: Window(aplc, padding())
{
}

void render() const override;

protected:
static dim_t padding();

private:
using Element::adim;
using Element::ahgt;
using Element::aplc;
using Element::apos;
using Element::awth;
using Element::axpos;
using Element::aypos;
};

template<>
inline dim_t WindowPadd<WindowType::Bare>::padding()
{
return {0, 0};
}

template<>
inline dim_t WindowPadd<WindowType::Border>::padding()
{
return {2, 2};
}

template<>
inline dim_t WindowPadd<WindowType::Box>::padding()
{
return {2, 2};
}

template<>
inline dim_t WindowPadd<WindowType::BorderBox>::padding()
{
return {4, 2};
}

template<>
void WindowPadd<WindowType::Bare>::render() const;

template<>
void WindowPadd<WindowType::Border>::render() const;

template<>
void WindowPadd<WindowType::Box>::render() const;

template<>
void WindowPadd<WindowType::BorderBox>::render() const;

} // namespace display

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

@@ -5,18 +5,11 @@

namespace display
{

place_t WindowPivot_place(place_t aplc, // NOLINT
piv_t piv,
dim_t dim,
dim_t padding);

template<typename T>
requires(std::is_base_of_v<Window, T>)
class WindowPivot : public T
class WindowPivot : public Window
{
public:
WindowPivot(place_t aplc, piv_t piv, dim_t dim)
: T(WindowPivot_place(aplc, piv, dim, T::padding()))
WindowPivot(place_t aplc, padd_t padd, piv_t piv, dim_t dim)
: Window(place(aplc, piv, dim + padd), padd)
, m_piv(piv)
, m_dim(dim)
{

@@ -24,10 +17,12 @@ public:


void resize(place_t aplc) override
{
T::resize(WindowPivot_place(aplc, m_piv, m_dim, T::padding()));
Window::resize(place(aplc, m_piv, m_dim + padd()));
}

private:
static place_t place(place_t aplc, piv_t piv, dim_t dim);

piv_t m_piv;
dim_t m_dim;
};

diff --git a/ source/window.cpp b/ source/window.cpp

@@ -7,6 +7,41 @@

namespace display
{

void Window::render() const
{
const auto space = std::string(awth(), ' ');

for (sz_t i = aypos(); i < aypos() + m_padd.top; i++) {
set_cursor(i, axpos()) << space;
}

for (sz_t i = aypos() + ahgt() - m_padd.bottom; i < aypos() + ahgt(); i++) {
set_cursor(i, axpos()) << space;
}
}

void Window::render_border() const
{
set_cursor(aypos(), axpos());
std::cout << "┌";
for (sz_t i = 2; i < awth(); i++) {
std::cout << "─";
}
std::cout << "┐";

for (sz_t i = aypos() + 1; i < aypos() + ahgt(); i++) {
set_cursor(i, axpos()) << "│";
set_cursor(i, axpos() + awth() - 1) << "│";
}

set_cursor(aypos() + ahgt() - 1, axpos());
std::cout << "└";
for (sz_t i = 2; i < awth(); i++) {
std::cout << "─";
}
std::cout << "┘";
}

void Window::clear() const
{
std::cout << alec::background_v<alec::Color::DEFAULT>;

@@ -37,27 +72,36 @@ std::ostream& Window::line_next() const

return null;
}

return set_cursor(m_ypos++, xpos());
return set_cursor(m_ypos++, axpos());
}

void Window::line_empty() const
{
line_next() << std::string(wth(), ' ');
line_next() << std::string(awth(), ' ');
}

void Window::line_left(const std::string& text) const
{
line_next() << std::format("{:<{}}", text, wth());
const auto left = std::string(m_padd.left, ' ');
const auto right = std::string(m_padd.right, ' ');

line_next() << left << std::format("{:<{}}", text, wth()) << right;
}

void Window::line_center(const std::string& text) const
{
line_next() << std::format("{:^{}}", text, wth());
const auto left = std::string(m_padd.left, ' ');
const auto right = std::string(m_padd.right, ' ');

line_next() << left << std::format("{:^{}}", text, wth()) << right;
}

void Window::line_right(const std::string& text) const
{
line_next() << std::format("{:>{}}", text, wth());
const auto left = std::string(m_padd.left, ' ');
const auto right = std::string(m_padd.right, ' ');

line_next() << left << std::format("{:>{}}", text, wth()) << right;
}

} // namespace display

diff --git a/ source/window_padd.cpp b/ source/window_padd.cpp

@@ -1,72 +0,0 @@

#include <iostream>

#include "display/window_padd.hpp"

namespace display
{

template<>
void WindowPadd<WindowType::Bare>::render() const
{
}

template<>
void WindowPadd<WindowType::Border>::render() const
{
set_cursor(aypos(), axpos()) << std::string(awth(), ' ');

for (sz_t i = ypos(); i < ypos() + hgt(); i++) {
set_cursor(i, axpos()) << ' ';
set_cursor(i, axpos() + awth() - 1) << ' ';
}

set_cursor(aypos() + ahgt() - 1, axpos()) << std::string(awth(), ' ');
}

template<>
void WindowPadd<WindowType::Box>::render() const
{
set_cursor(aypos(), axpos());
std::cout << "┌";
for (sz_t i = 0; i < wth(); i++) {
std::cout << "─";
}
std::cout << "┐";

for (sz_t i = ypos(); i < ypos() + hgt(); i++) {
set_cursor(i, axpos()) << "│";
set_cursor(i, axpos() + awth() - 1) << "│";
}

set_cursor(aypos() + ahgt() - 1, axpos());
std::cout << "└";
for (sz_t i = 0; i < wth(); i++) {
std::cout << "─";
}
std::cout << "┘";
}

template<>
void WindowPadd<WindowType::BorderBox>::render() const
{
set_cursor(aypos(), axpos());
std::cout << "┌─";
for (sz_t i = 0; i < wth(); i++) {
std::cout << "─";
}
std::cout << "─┐";

for (sz_t i = ypos(); i < ypos() + hgt(); i++) {
set_cursor(i, axpos()) << "│ ";
set_cursor(i, axpos() + awth() - 2) << " │";
}

set_cursor(aypos() + ahgt() - 1, axpos());
std::cout << "└─";
for (sz_t i = 0; i < wth(); i++) {
std::cout << "─";
}
std::cout << "─┘";
}

} // namespace display

diff --git a/ source/window_pivot.cpp b/ source/window_pivot.cpp

@@ -1,16 +1,17 @@

#include "display/window_pivot.hpp"

#include "display/utility.hpp"

namespace display
{

place_t WindowPivot_place(place_t aplc, piv_t piv, dim_t dim, dim_t padding)
place_t WindowPivot::place(place_t aplc, piv_t piv, dim_t dim)
{
const auto [cols, rows] = aplc.dim;
const sz_t colsh = cols / 2;
const sz_t rowsh = rows / 2;

const auto [wdth, hght] = dim + padding;
const auto [wdth, hght] = dim;
const sz_t wdthm = wdth / 2;
const sz_t hghtm = hght / 2;