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 0a2055e0d50fb99f07a402275c0bab779453f22c
parent 3af9fe76afbf1bfe6f67d7125327dfb2899ce0e7
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Mon, 17 Feb 2025 12:23:22 +0100

Window line drawing methods

* Windows's aplace represents the rendering area
* Layout gives entirety of it's space to window.
* Window figures out which part it'll occupy
* This happens during construction and resize
* This method has to be static so it can be called during construction

Diffstat:
M CMakeLists.txt | +++ --
M example/example.cpp | ++++ ---------
M example/navig/navig.cpp | +++++++++ -----------------------------
M include/display/element.hpp | + ---
M include/display/window.hpp | ++++++++++
M include/display/window_pivot.hpp | +++++++++++++ --------
A source/window.cpp | +++++++++++++++++++++++++++++++++++++

7 files changed, 77 insertions(+), 51 deletions(-)


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

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


project(
display
VERSION 0.1.25
VERSION 0.1.26
DESCRIPTION "TUI library"
HOMEPAGE_URL "https://example.com/"
HOMEPAGE_URL "git://git.dimitrijedobrota.com/display.git"
LANGUAGES CXX
)

@@ -20,6 +20,7 @@ find_package(alec 0.1.13 CONFIG REQUIRED)

add_library(
display_display
source/display.cpp
source/window.cpp
)
target_link_libraries(display_display PUBLIC alec::alec)
add_library(display::display ALIAS display_display)

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

@@ -1,5 +1,4 @@

#include <iostream>
#include <string>

#include <alec/alec.hpp>

@@ -24,17 +23,13 @@ public:

void render() const override
{
static int color_red = 0;
color_red = (color_red + 25) % 256;

const auto [pos, dim] = place();
const auto [x, y] = pos;
const auto [w, h] = dim;

color_red = (color_red + 25) % 256;
std::cout << alec::background(color_red, 65, 65);

for (auto ypos = y; ypos < y + h; ypos++) {
std::cout << alec::cursor_position(ypos + 1, x + 1);
std::cout << std::string(w, ' ');
line_empty(/* reset = */ true);
for (std::size_t i = 1; i < ahgt(); i++) {
line_empty();
}

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

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

@@ -1,4 +1,3 @@

#include <format>
#include <iostream>
#include <stack>
#include <string>

@@ -37,51 +36,32 @@ public:

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

const auto [apos, adim] = place();
const auto [x, y] = apos;
const auto [w, h] = adim;

display::sz_t ypos = y;

const auto cursor = [&]() { return alec::cursor_position(++ypos, x + 1); };

for (std::size_t i = 0; i < h; i++) {
std::cout << cursor() << std::string(w, ' ');
line_empty(/* reset = */ true);
for (std::size_t i = 1; i < ahgt(); i++) {
line_empty();
}
std::cout << std::flush;
}

void render() const override
{
const auto [apos, adim] = place();
const auto [x, y] = apos;
const auto [w, h] = adim;

display::sz_t ypos = y;

auto cursor = [&]() { return alec::cursor_position(++ypos, x + 1); };
auto empty = [&]() { std::cout << cursor() << std::string(w, ' '); };

auto center = [&](const std::string& value)
{ std::cout << cursor() << std::format("{:^{}}", value, w); };

auto right = [&](const std::string& value)
{ std::cout << cursor() << std::format("{:>{}} ", value, w - 1); };

std::cout << alec::background_v<alec::Color::BLUE>;

empty(), center(m_menu.title), empty();
line_empty(/* reset = */ true);
line_center(m_menu.title);
line_empty();
for (std::size_t i = 0; i < m_menu.items.size(); i++) {
if (m_selected == i) {
std::cout << alec::foreground_v<alec::Color::GREEN>;
}

right(m_menu.items[i].prompt);
line_right(m_menu.items[i].prompt);

if (m_selected == i) {
std::cout << alec::foreground_v<alec::Color::DEFAULT>;
}
}
empty();
line_empty();

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

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

@@ -3,9 +3,7 @@

#include "display/types.hpp"

namespace display
{

class Element
{ class Element
{
public:
explicit Element(aplace_t aplc)

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

@@ -15,6 +15,16 @@ public:

}

void input(event& /* unused */) override {}

protected:
std::ostream& next_line(bool reset = false) const;
void line_empty(bool reset = false) const;
void line_left(const std::string& text) const;
void line_center(const std::string& text) const;
void line_right(const std::string& text) const;

private:
mutable display::sz_t m_ypos = 0;
};

} // namespace display

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

@@ -1,7 +1,7 @@

#pragma once

#include "display/window.hpp"
#include "display/utility.hpp"
#include "display/window.hpp"

namespace display
{

@@ -10,20 +10,25 @@ class WindowPivot : public Window

{
public:
WindowPivot(aplace_t aplc, piv_t piv, dim_t dim)
: Window(aplc)
: Window(place(aplc, piv, dim))
, m_piv(piv)
, m_dim(dim)
{
}

void resize(aplace_t aplc) override
{
Window::resize(place(aplc, m_piv, m_dim));
}

protected:
aplace_t place() const
static aplace_t place(aplace_t aplc, piv_t piv, dim_t dim)
{
const auto [cols, rows] = adim();
const auto [cols, rows] = aplc.adim;
const sz_t colsh = cols / 2;
const sz_t rowsh = rows / 2;

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

@@ -34,7 +39,7 @@ protected:


using display::add_lim, display::sub_lim;

switch (m_piv.x) {
switch (piv.x) {
case PvtX::Left:
start.x = 0;
end.x = add_lim(start.x, wdth, cols);

@@ -49,7 +54,7 @@ protected:

break;
}

switch (m_piv.y) {
switch (piv.y) {
case PvtY::Top:
start.y = 0;
end.y = add_lim(start.y, hght, rows);

@@ -64,7 +69,7 @@ protected:

break;
}

return {apos() + start, end - start};
return {aplc.apos + start, end - start};
}

private:

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

@@ -0,0 +1,37 @@

#include <format>
#include <iostream>

#include "display/window.hpp"

namespace display
{

std::ostream& Window::next_line(bool reset) const
{
if (reset) {
m_ypos = aypos();
}
return std::cout << alec::cursor_position(++m_ypos, axpos() + 1);
}

void Window::line_empty(bool reset) const
{
next_line(reset) << std::string(awth(), ' ');
}

void Window::line_left(const std::string& text) const
{
next_line() << std::format(" {:<{}} ", text, awth() - 2);
}

void Window::line_center(const std::string& text) const
{
next_line() << std::format("{:^{}}", text, awth());
}

void Window::line_right(const std::string& text) const
{
next_line() << std::format(" {:>{}} ", text, awth() - 2);
}

} // namespace display