display

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

commit814dee099d96d33f03b392643ab6720446680955
parentc451c9d592719287e5fe70b35cc303c4a233dce0
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateSun, 9 Feb 2025 12:06:12 +0100

Use Singleton for better RAII and consistency

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

4 files changed, 71 insertions(+), 49 deletions(-)


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

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

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

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

@@ -33,8 +33,10 @@ int renderer(display::Window& win)

int main()
{
try {
display::LayoutFree layout;
using display::Display;
auto& disp = Display::display();
display::LayoutFree layout;
auto redraw = [&]()
{
const auto [cols, rows] = alec::get_screen_size();

@@ -66,17 +68,19 @@ int main()

layout.append({{}, {20, 10}, {PvtX::Left, PvtY::Center}});
layout.append({{}, {20, 10}, {PvtX::Center, PvtY::Center}});
display::start();
redraw();
using display::event;
while (true) {
const auto event = display::get_event();
if (event.type() == display::event::Type::RESIZE) {
const auto event = disp.get_event();
if (event.type() == event::Type::RESIZE) {
std::cout << alec::erase_display_v<alec::Motion::WHOLE>;
redraw();
continue;
}
if (event.type() == display::event::Type::KEY && event.key() == 'q') {
if (event.type() == event::Type::KEY && event.key() == 'q') {
break;
}
}

@@ -85,7 +89,5 @@ int main()

std::cout << err.what() << '\n' << std::flush;
}
display::stop();
return 0;
}

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

@@ -5,13 +5,32 @@

namespace display
{
using exit_f = void();
using event = alec::event;
void exit();
void start(exit_f f_exit = exit);
void stop(bool force = false);
class Display
{
public:
static Display& display();
Display(const Display&) = delete;
Display(Display&&) = delete;
Display& operator=(const Display&) = delete;
Display& operator=(Display&&) = delete;
event get_event();
bool get_resized() const;
void set_resized();
void reset_resized();
private:
Display();
~Display();
static void handle_sigwinch(int /* unused */);
static bool is_resize_track;
event get_event();
bool m_is_resized = false;
};
} // namespace display

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

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

#include <csignal>
#include <stdexcept>
#include "display/display.hpp"

@@ -20,40 +19,16 @@ inline void write()

namespace display
{
static int start_count = 0; // NOLINT
static bool resized = false; // NOLINT
bool Display::is_resize_track = false;
void handle_sigwinch(int /* unused */) // NOLINT misc-use-internal-linkage
Display& Display::display()
{
resized = true;
static Display instance;
return instance;
}
event get_event()
Display::Display()
{
if (resized) {
resized = false;
return {event::Type::RESIZE, 0, 0};
}
return alec::get_event();
}
void exit()
{
stop(/* force= */ true);
}
void start(exit_f f_exit)
{
if (start_count++ > 0) {
// already started
return;
}
if (atexit(f_exit) != 0) {
throw std::runtime_error("Can't register new exit function");
}
struct sigaction old_sig_action = {};
sigaction(SIGWINCH, nullptr, &old_sig_action);
if (old_sig_action.sa_handler != SIG_IGN) {

@@ -64,6 +39,7 @@ void start(exit_f f_exit)

new_sig_action.sa_flags = SA_RESTART;
sigaction(SIGWINCH, &new_sig_action, nullptr);
is_resize_track = true;
}
alec::init_buffer(STDIN_FILENO);

@@ -71,16 +47,41 @@ void start(exit_f f_exit)

write<alec::cursor_hide_v>();
}
void stop(bool force)
Display::~Display()
{
if (!force && --start_count > 0) {
// still need to keep open
return;
}
alec::dest_buffer();
write<alec::cursor_show_v>();
write<alec::abuf_disable_v>();
}
void Display::handle_sigwinch(int /* unused */)
{
Display::display().set_resized();
}
event Display::get_event() // NOLINT
{
if (is_resize_track && m_is_resized) {
Display::reset_resized();
return {event::Type::RESIZE, 0, 0};
}
return alec::get_event();
}
void Display::set_resized()
{
m_is_resized = true;
}
void Display::reset_resized()
{
m_is_resized = false;
}
bool Display::get_resized() const
{
return m_is_resized;
}
} // namespace display