displayLayout and Rendering TUI library |
git clone git://git.dimitrijedobrota.com/display.git |
Log | Files | Refs | README | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | |
commit | 6bc9907460f1b64a63df06d9088dd9748711d06b |
parent | 814dee099d96d33f03b392643ab6720446680955 |
author | Dimitrije Dobrota <mail@dimitrijedobrota.com> |
date | Mon, 10 Feb 2025 11:15:23 +0100 |
Tight coupling that automaticaly handles resize
Diffstat:M | CMakeLists.txt | | | ++- |
M | example/example.cpp | | | ++++++++++++++++++++++++++---------------------------- |
M | include/display/display.hpp | | | +++++ |
M | include/display/layout.hpp | | | +++++++++++++++++- |
A | include/display/screen.hpp | | | +++++++++++++++++++++++++++++++ |
M | include/display/types.hpp | | | +++++++ |
M | include/display/window.hpp | | | +++++++ |
M | source/display.cpp | | | ++ |
M | source/layout.cpp | | | ++++++++++++++ |
A | source/screen.cpp | | | +++++++++++++++++++++++++++++ |
M | source/window.cpp | | | ++-- |
11 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -4,7 +4,7 @@ include(cmake/prelude.cmake)
project(
display
VERSION 0.1.11
VERSION 0.1.12
DESCRIPTION "TUI library"
HOMEPAGE_URL "https://example.com/"
LANGUAGES CXX
@@ -21,6 +21,7 @@ add_library(
display_display
source/display.cpp
source/layout.cpp
source/screen.cpp
source/window.cpp
)
target_link_libraries(display_display PUBLIC alec::alec)
diff --git a/example/example.cpp b/example/example.cpp
@@ -28,35 +28,35 @@ int renderer(display::Window& win)
return 0;
}
void recalculator(display::LayoutFree& layout)
{
const auto [width, height] = layout.dim();
const display::sz_t midw = width / 2;
const display::sz_t midh = height / 2;
layout[4].pos() = {0, 0};
layout[5].pos() = {midw, 0};
layout[6].pos() = {width, 0};
layout[7].pos() = {width, midh};
layout[0].pos() = {width, height};
layout[1].pos() = {midw, height};
layout[2].pos() = {0, height};
layout[3].pos() = {0, midh};
layout[8].pos() = {midw, midh};
}
} // namespace
int main()
{
try {
using display::Display;
using display::PvtX, display::PvtY;
auto& disp = Display::display();
display::LayoutFree layout;
auto redraw = [&]()
{
const auto [cols, rows] = alec::get_screen_size();
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);
};
using display::PvtX, display::PvtY;
display::LayoutFree layout(recalculator);
disp.screen().set_layout(&layout);
layout.append({{}, {20, 10}, {PvtX::Left, PvtY::Top}});
layout.append({{}, {20, 10}, {PvtX::Center, PvtY::Top}});
@@ -68,19 +68,17 @@ int main()
layout.append({{}, {20, 10}, {PvtX::Left, PvtY::Center}});
layout.append({{}, {20, 10}, {PvtX::Center, PvtY::Center}});
redraw();
using display::event;
for (disp.set_resized(); true;) {
using display::event;
while (true) {
const auto event = disp.get_event();
if (event.type() == event::Type::RESIZE) {
const auto evnt = disp.get_event();
if (evnt.type() == event::Type::RESIZE) {
std::cout << alec::erase_display_v<alec::Motion::WHOLE>;
redraw();
layout.render(renderer);
continue;
}
if (event.type() == event::Type::KEY && event.key() == 'q') {
if (evnt.type() == event::Type::KEY && evnt.key() == 'q') {
break;
}
}
diff --git a/include/display/display.hpp b/include/display/display.hpp
@@ -2,6 +2,8 @@
#include <alec/alec.hpp>
#include "display/screen.hpp"
namespace display
{
@@ -17,6 +19,8 @@ public:
Display& operator=(const Display&) = delete;
Display& operator=(Display&&) = delete;
Screen& screen() { return m_screen; }
event get_event();
bool get_resized() const;
@@ -30,6 +34,7 @@ private:
static void handle_sigwinch(int /* unused */);
static bool is_resize_track;
Screen m_screen;
bool m_is_resized = false;
};
diff --git a/include/display/layout.hpp b/include/display/layout.hpp
@@ -7,21 +7,37 @@
namespace display
{
class Screen;
class LayoutFree
{
public:
using render_f = int(Window&);
using recalc_f = void(LayoutFree&);
LayoutFree(recalc_f f_recalc) // NOLINT
: m_recalc(f_recalc)
{
}
dim_t dim() const;
Screen* get_screen() { return m_screen; }
void set_screen(Screen* screen) { m_screen = screen; }
const auto& operator[](std::size_t idx) const { return m_windows[idx]; }
auto& operator[](std::size_t idx) { return m_windows[idx]; }
void append(Window window);
void recalc();
int render(render_f renderer);
private:
std::vector<Window> m_windows;
bool m_is_sorted = true;
recalc_f* m_recalc;
Screen* m_screen = nullptr;
};
class LayoutRigid
diff --git a/include/display/screen.hpp b/include/display/screen.hpp
@@ -0,0 +1,31 @@
#pragma once
#include "display/types.hpp"
namespace display
{
class LayoutFree;
class Screen
{
public:
Screen(dim_t dim) // NOLINT
: m_dim(dim)
{
}
const auto& dim() const { return m_dim; }
LayoutFree* get_layout() { return m_layout; }
void set_layout(LayoutFree* layout);
void resize(dim_t dim);
private:
dim_t m_dim;
LayoutFree* m_layout = nullptr;
};
} // namespace display
diff --git a/include/display/types.hpp b/include/display/types.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <utility>
namespace display
{
@@ -15,6 +16,12 @@ struct dim_t
{
}
dim_t(std::pair<sz_t, sz_t> pair) // NOLINT
: width(std::get<0>(pair))
, height(std::get<1>(pair))
{
}
sz_t width;
sz_t height;
};
diff --git a/include/display/window.hpp b/include/display/window.hpp
@@ -7,6 +7,8 @@
namespace display
{
class LayoutFree;
class Window
{
public:
@@ -26,12 +28,17 @@ public:
const auto& piv() const { return m_piv; }
auto& piv() { return m_piv; }
LayoutFree* get_layout() { return m_layout; }
void set_layout(LayoutFree* layout) { m_layout = layout; }
std::optional<place_t> place() const;
private:
pos_t m_pos;
dim_t m_dim;
piv_t m_piv;
LayoutFree* m_layout = nullptr;
};
} // namespace display
diff --git a/source/display.cpp b/source/display.cpp
@@ -28,6 +28,7 @@ Display& Display::display()
}
Display::Display()
: m_screen(alec::get_screen_size())
{
struct sigaction old_sig_action = {};
sigaction(SIGWINCH, nullptr, &old_sig_action);
@@ -71,6 +72,7 @@ event Display::get_event() // NOLINT
void Display::set_resized()
{
m_screen.resize(alec::get_screen_size());
m_is_resized = true;
}
diff --git a/source/layout.cpp b/source/layout.cpp
@@ -3,15 +3,29 @@
#include "display/layout.hpp"
#include "display/screen.hpp"
#include "display/window.hpp"
namespace display
{
dim_t LayoutFree::dim() const
{
return m_screen != nullptr ? m_screen->dim() : dim_t();
}
void LayoutFree::append(Window window)
{
m_windows.push_back(window);
m_windows.back().set_layout(this);
m_is_sorted = false;
}
void LayoutFree::recalc()
{
m_recalc(*this);
}
int LayoutFree::render(render_f renderer)
{
static std::vector<std::uint8_t> idxs;
diff --git a/source/screen.cpp b/source/screen.cpp
@@ -0,0 +1,29 @@
#include "display/screen.hpp"
#include "display/layout.hpp"
namespace display
{
void Screen::set_layout(LayoutFree* layout)
{
if (m_layout != nullptr) {
m_layout->set_screen(nullptr);
}
m_layout = layout;
if (m_layout != nullptr) {
m_layout->set_screen(this);
}
}
void Screen::resize(dim_t dim)
{
m_dim = dim;
if (m_layout != nullptr) {
m_layout->recalc();
}
}
} // namespace display
diff --git a/source/window.cpp b/source/window.cpp
@@ -1,6 +1,6 @@
#include "display/window.hpp"
#include "alec/alec.hpp"
#include "display/layout.hpp"
#include "display/utility.hpp"
namespace display
@@ -8,7 +8,7 @@ namespace display
std::optional<place_t> Window::place() const
{
const auto [cols, rows] = alec::get_screen_size();
const auto [cols, rows] = m_layout->dim();
const auto [posx, posy, _] = pos();
if (posx > cols || posy > rows) {