Add C++ bindings

pull/292/head
Marek Habersack 4 years ago committed by Nick Black
parent 22f71c9a80
commit 75a90461dd

@ -65,9 +65,15 @@ target_link_directories(notcurses
)
endif()
if(CMAKE_BUILD_TYPE STREQUAL Debug)
set(DEBUG_OPTIONS -g -O0)
else()
set(DEBUG_OPTIONS -O2)
endif()
target_compile_options(notcurses
PRIVATE
-Wall -Wextra -W -Wshadow
-Wall -Wextra -W -Wshadow ${DEBUG_OPTIONS}
)
target_compile_definitions(notcurses
PUBLIC
@ -76,6 +82,140 @@ target_compile_definitions(notcurses
FORTIFY_SOURCE=2 _GNU_SOURCE SOURCE_DEFAULT
)
# libnotcurses++
set(NCPP_SOURCES
src/libcpp/NotCurses.cc
src/libcpp/PanelReel.cc
src/libcpp/Plane.cc
src/libcpp/Root.cc
src/libcpp/Tablet.cc
src/libcpp/Visual.cc
)
add_library(
notcurses++
SHARED
${NCPP_SOURCES}
)
add_library(
notcurses++-static
STATIC
${NCPP_SOURCES}
)
set_target_properties(
notcurses++-static PROPERTIES
OUTPUT_NAME notcurses++
)
set_target_properties(
notcurses++ PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
OUTPUT_NAME "notcurses++")
set(NCPP_INCLUDE_DIRS
include
"${PROJECT_BINARY_DIR}/include"
"${TERMINFO_INCLUDE_DIRS}"
)
target_include_directories(notcurses++
PRIVATE ${NCPP_INCLUDE_DIRS}
)
target_include_directories(notcurses++-static
PRIVATE ${NCPP_INCLUDE_DIRS}
)
target_link_libraries(notcurses++
PRIVATE
notcurses)
set(NCPP_COMPILE_OPTIONS
-Wall
-Wextra
-W
-Wshadow
-Wformat
-Werror=format-security
-Wnull-dereference
-Wmisleading-indentation
-Wunused
-Wpedantic
-Wsuggest-override
-Wno-c99-extensions
-fno-strict-aliasing
-ffunction-sections
-funswitch-loops
-finline-limit=300
-fstack-protector
-fno-rtti
-fno-exceptions
-fpic
${DEBUG_OPTIONS}
)
set(NCPP_COMPILE_DEFINITIONS_PUBLIC
FORTIFY_SOURCE=2 _GNU_SOURCE SOURCE_DEFAULT
)
set(NCPP_COMPILE_DEFINITIONS_PRIVATE
_XOPEN_SOURCE # wcwidth(3) requires _XOPEN_SOURCE, and is in our headers
)
target_compile_options(notcurses++
PRIVATE
${NCPP_COMPILLE_OPTIONS}
)
target_compile_options(notcurses++-static
PRIVATE
${NCPP_COMPILLE_OPTIONS}
)
target_compile_definitions(notcurses++
PUBLIC
${NCPP_COMPILE_DEFINITIONS_PUBLIC}
PRIVATE
${NCPP_COMPILE_DEFINITIONS_PRIVATE}
)
target_compile_definitions(notcurses++-static
PUBLIC
${NCPP_COMPILE_DEFINITIONS_PUBLIC}
PRIVATE
${NCPP_COMPILE_DEFINITIONS_PRIVATE}
)
file(GLOB NCPP_HEADERS
CONFIGURE_DEPENDS
LIST_DIRECTORIES false
${CMAKE_SOURCE_DIR}/include/ncpp/*.hh)
file(GLOB NCPP_INTERNAL_HEADERS
CONFIGURE_DEPENDS
LIST_DIRECTORIES false
${CMAKE_SOURCE_DIR}/include/ncpp/internal/*.hh)
install(FILES ${NCPP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ncpp)
install(FILES ${NCPP_INTERNAL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ncpp/internal)
install(
TARGETS notcurses++
LIBRARY
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT Libraries
NAMELINK_COMPONENT Development
)
install(
TARGETS notcurses++-static
LIBRARY
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT Libraries
NAMELINK_COMPONENT Development
)
# notcurses-demo
file(GLOB DEMOSRCS CONFIGURE_DEPENDS src/demo/*.c)
add_executable(notcurses-demo ${DEMOSRCS})
@ -91,7 +231,7 @@ target_link_libraries(notcurses-demo
)
target_compile_options(notcurses-demo
PRIVATE
-Wall -Wextra -W -Wshadow
-Wall -Wextra -W -Wshadow ${DEBUG_OPTIONS}
)
target_compile_definitions(notcurses-demo
PRIVATE
@ -107,7 +247,7 @@ foreach(f ${POCSRCS})
PRIVATE include "${TERMINFO_INCLUDE_DIRS}"
)
target_link_libraries(${fe}
PRIVATE notcurses "${TERMINFO_LIBRARIES}"
PRIVATE notcurses notcurses++ "${TERMINFO_LIBRARIES}"
)
target_link_directories(${fe}
PRIVATE "${TERMINFO_LIBRARY_DIRS}"
@ -167,11 +307,11 @@ target_include_directories(notcurses-input
)
target_link_libraries(notcurses-input
PRIVATE
notcurses
notcurses notcurses++
)
target_compile_options(notcurses-input
PRIVATE
-Wall -Wextra -W -Wshadow
-Wall -Wextra -W -Wshadow ${DEBUG_OPTIONS}
)
target_compile_definitions(notcurses-input
PRIVATE
@ -188,11 +328,11 @@ target_include_directories(notcurses-planereel
)
target_link_libraries(notcurses-planereel
PRIVATE
notcurses
notcurses notcurses++
)
target_compile_options(notcurses-planereel
PRIVATE
-Wall -Wextra -W -Wshadow
-Wall -Wextra -W -Wshadow ${DEBUG_OPTIONS}
)
target_compile_definitions(notcurses-planereel
PRIVATE
@ -215,7 +355,7 @@ target_link_directories(notcurses-view
)
target_link_libraries(notcurses-view
PRIVATE
notcurses
notcurses notcurses++
PRIVATE
"${AVUTIL_LIBRARIES}"
"${AVFORMAT_LIBRARIES}"
@ -223,7 +363,7 @@ target_link_libraries(notcurses-view
)
target_compile_options(notcurses-view
PRIVATE
-Wall -Wextra -W -Wshadow
-Wall -Wextra -W -Wshadow ${DEBUG_OPTIONS}
)
target_compile_definitions(notcurses-view
PRIVATE
@ -246,7 +386,7 @@ target_link_libraries(notcurses-tester
)
target_compile_options(notcurses-tester
PRIVATE
-Wall -Wextra -W -Wshadow
-Wall -Wextra -W -Wshadow ${DEBUG_OPTIONS}
)
target_compile_definitions(notcurses-tester
PRIVATE
@ -265,6 +405,15 @@ configure_file(tools/notcurses.pc.in
@ONLY
)
configure_file(tools/notcurses++.pc.in
${CMAKE_CURRENT_BINARY_DIR}/notcurses++.pc
@ONLY
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/notcurses++.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
include(CMakePackageConfigHelpers)
configure_file(tools/version.h.in include/version.h)

17
debian/control vendored

@ -4,7 +4,7 @@ Maintainer: Nick Black <dankamongmen@gmail.com>
Build-Depends: debhelper-compat (= 12), cmake (>= 3.13), pkg-config (>= 0.29),
libncurses-dev (>= 6.1), libavformat-dev (>= 57.0), libswscale-dev (>= 5.0),
libavutil-dev (>= 56.0), pandoc (>= 1.19.2.4), python3-all-dev (>= 3.2),
python-cffi
python-cffi, g++ (>= 4:7.0.0-0)
Standards-Version: 4.4.1.1
Section: libs
Homepage: https://nick-black.com/dankwiki/index.php/notcurses
@ -31,6 +31,21 @@ Description: Shared libraries for notcurses TUI
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
Package: libnotcurses++-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libnotcurses-dev (>= 1.0.0-1), libnotcurses++1 (= ${binary:Version}), ${misc:Depends}
Description: Development files for notcurses++
Files necessary for development using notcurses++, a C++ wrapper for notcurses
Package: libnotcurses++1
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Shared libraries for notcurses++
notcurses++ is a C++ binding for the notcurses TUI library
Package: notcurses-bin
Architecture: any
Multi-Arch: foreign

18
debian/copyright vendored

@ -20,6 +20,24 @@ License: Apache-2.0
On Debian systems, the complete text of the Apache version 2.0 license
can be found in "/usr/share/common-licenses/Apache-2.0".
Files: src/libcpp/* include/ncpp/*
Copyright: 2019-2020 Marek Habersack <grendel@twistedcode.net>
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
https://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHnot WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the complete text of the Apache version 2.0 license
can be found in "/usr/share/common-licenses/Apache-2.0".
Files: debian/*
Copyright: 2019 Nick Black <dankamongmen@gmail.com>
License: GPL-2+

@ -0,0 +1,4 @@
usr/include/ncpp
usr/lib/*/libnotcurses++.so
usr/lib/*/libnotcurses++.a
usr/lib/*/pkgconfig/notcurses++.pc

@ -0,0 +1 @@
usr/lib/*/libnotcurses++.so.*

@ -0,0 +1,20 @@
libnotcurses++.so.1 libnotcurses++1 #MINVER#
_ZN4ncpp5Plane11unmap_planeEPS0_@Base 1.1.0
_ZN4ncpp5Plane15plane_map_mutexE@Base 1.1.0
_ZN4ncpp5Plane9map_planeEP7ncplanePS0_@Base 1.1.0
_ZN4ncpp5Plane9plane_mapE@Base 1.1.0
_ZN4ncpp6Tablet10map_tabletEP6tablet@Base 1.1.0
_ZN4ncpp6Tablet10tablet_mapE@Base 1.1.0
_ZN4ncpp6Tablet12unmap_tabletEPS0_@Base 1.1.0
_ZN4ncpp6Tablet16tablet_map_mutexE@Base 1.1.0
_ZN4ncpp9NotCurses25default_notcurses_optionsE@Base 1.1.0
_ZN4ncpp9NotCurses4initERK17notcurses_optionsP8_IO_FILE@Base 1.1.0
_ZN4ncpp9NotCurses7get_topEv@Base 1.1.0
_ZN4ncpp9NotCurses9_instanceE@Base 1.1.0
_ZN4ncpp9NotCursesD1Ev@Base 1.1.0
_ZN4ncpp9NotCursesD2Ev@Base 1.1.0
_ZN4ncpp9PanelReel15default_optionsE@Base 1.1.0
_ZNK4ncpp4Root13get_notcursesEv@Base 1.1.0
_ZNK4ncpp6Tablet9get_planeEv@Base 1.1.0
_ZNK4ncpp6Visual9get_planeEv@Base 1.1.0
_ZNK4ncpp9PanelReel9get_planeEv@Base 1.1.0

@ -1,5 +1,5 @@
usr/include
usr/lib/*/*.so
usr/lib/*/pkgconfig/*.pc
usr/include/notcurses.h
usr/lib/*/libnotcurses.so
usr/lib/*/pkgconfig/notcurses.pc
usr/lib/*/cmake/*
usr/share/man/man3/*

@ -1 +1 @@
usr/lib/*/*.so.*
usr/lib/*/libnotcurses.so.*

@ -0,0 +1,239 @@
#ifndef __NCPP_CELL_HH
#define __NCPP_CELL_HH
#include <map>
#include <mutex>
#include <notcurses.h>
#include "Root.hh"
#include "CellStyle.hh"
namespace ncpp
{
class NCPP_API_EXPORT Cell : public Root
{
public:
static constexpr uint64_t WideAsianMask = CELL_WIDEASIAN_MASK;
static constexpr uint64_t FGDefaultMask = CELL_FGDEFAULT_MASK;
static constexpr uint64_t FGMask = CELL_FG_MASK;
static constexpr uint64_t BGDefaultMask = CELL_BGDEFAULT_MASK;
static constexpr uint64_t BGMask = CELL_BG_MASK;
static constexpr uint64_t AlphaMask = CELL_ALPHA_MASK;
static constexpr uint32_t AlphaShift = CELL_ALPHA_SHIFT;
static constexpr int AlphaHighContrast = CELL_ALPHA_HIGHCONTRAST;
static constexpr int AlphaTransparent = CELL_ALPHA_TRANSPARENT;
static constexpr int AlphaBlend = CELL_ALPHA_BLEND;
static constexpr int AlphaOpaque = CELL_ALPHA_OPAQUE;
public:
Cell () noexcept
{
init ();
}
explicit Cell (uint32_t c) noexcept
{
_cell = CELL_SIMPLE_INITIALIZER (c);
}
explicit Cell (uint32_t c, uint32_t a, uint64_t chan) noexcept
{
_cell = CELL_INITIALIZER (c, a, chan);
}
operator cell* () noexcept
{
return &_cell;
}
operator cell const* () const noexcept
{
return &_cell;
}
cell& get () noexcept
{
return _cell;
}
void init () noexcept
{
cell_init (&_cell);
}
uint64_t set_fchannel (uint32_t channel) noexcept
{
return cell_set_fchannel (&_cell, channel);
}
uint64_t blend_fchannel (unsigned channel, unsigned blends) noexcept
{
return cell_blend_fchannel (&_cell, channel, blends);
}
uint64_t set_bchannel (uint32_t channel) noexcept
{
return cell_set_bchannel (&_cell, channel);
}
uint64_t blend_bchannel (unsigned channel, unsigned blends) noexcept
{
return cell_blend_bchannel (&_cell, channel, blends);
}
void set_styles (CellStyle styles) noexcept
{
cell_styles_set (&_cell, static_cast<unsigned>(styles));
}
CellStyle get_styles () noexcept
{
return static_cast<CellStyle>(cell_styles (&_cell));
}
void styles_on (CellStyle styles) noexcept
{
cell_styles_on (&_cell, static_cast<unsigned>(styles));
}
void styles_off (CellStyle styles) noexcept
{
cell_styles_off (&_cell, static_cast<unsigned>(styles));
}
bool is_double_wide () const noexcept
{
return cell_double_wide_p (&_cell);
}
bool is_simple () const noexcept
{
return cell_simple_p (&_cell);
}
uint32_t get_edc_idx () const noexcept
{
return cell_egc_idx (&_cell);
}
unsigned get_bchannel () const noexcept
{
return cell_bchannel (&_cell);
}
unsigned get_fchannel () const noexcept
{
return cell_fchannel (&_cell);
}
unsigned get_fg () const noexcept
{
return cell_fg (&_cell);
}
unsigned get_bg () const noexcept
{
return cell_bg (&_cell);
}
unsigned get_fg_alpha () const noexcept
{
return cell_fg_alpha (&_cell);
}
bool is_fg_default () const noexcept
{
return cell_fg_default_p (&_cell);
}
bool set_fg_alpha (int alpha) noexcept
{
return cell_set_fg_alpha (&_cell, alpha) != -1;
}
unsigned get_bg_alpha () const noexcept
{
return cell_bg_alpha (&_cell);
}
bool set_bg_alpha (int alpha) noexcept
{
return cell_set_bg_alpha (&_cell, alpha) != -1;
}
unsigned get_fg_rgb (unsigned *r, unsigned *g, unsigned *b) const noexcept
{
return cell_fg_rgb (&_cell, r, g, b);
}
bool set_fg_rgb (int r, int g, int b, bool clipped = false) noexcept
{
if (clipped) {
cell_set_fg_rgb_clipped (&_cell, r, g, b);
return true;
}
return cell_set_fg_rgb (&_cell, r, g, b) != -1;
}
void set_fg (uint32_t channel) noexcept
{
cell_set_fg (&_cell, channel);
}
void set_fg_default () noexcept
{
cell_set_fg_default (&_cell);
}
unsigned get_bg_rgb (unsigned *r, unsigned *g, unsigned *b) const noexcept
{
return cell_bg_rgb (&_cell, r, g, b);
}
bool set_bg_rgb (int r, int g, int b, bool clipped = false) noexcept
{
if (clipped) {
cell_set_bg_rgb_clipped (&_cell, r, g, b);
return true;
}
return cell_set_bg_rgb (&_cell, r, g, b) != -1;
}
void set_bg (uint32_t channel) noexcept
{
cell_set_bg (&_cell, channel);
}
void set_bg_default () noexcept
{
cell_set_bg_default (&_cell);
}
bool is_bg_default () const noexcept
{
return cell_bg_default_p (&_cell);
}
bool has_no_foreground () const noexcept
{
return cell_noforeground_p (&_cell);
}
bool is_wide_right () const noexcept
{
return cell_wide_right_p (&_cell);
}
bool is_wide_left () const noexcept
{
return cell_wide_left_p (&_cell);
}
private:
cell _cell;
};
}
#endif

@ -0,0 +1,28 @@
#ifndef __NCPP_CELL_STYLE_HH
#define __NCPP_CELL_STYLE_HH
#include <cstdint>
#include <notcurses.h>
#include "_flag_enum_operator_helpers.hh"
namespace ncpp
{
enum class CellStyle : uint32_t
{
None = 0,
Standout = CELL_STYLE_STANDOUT,
Underline = CELL_STYLE_UNDERLINE,
Reverse = CELL_STYLE_REVERSE,
Blink = CELL_STYLE_BLINK,
Dim = CELL_STYLE_DIM,
Bold = CELL_STYLE_BOLD,
Invis = CELL_STYLE_INVIS,
Protect = CELL_STYLE_PROTECT,
Italic = CELL_STYLE_ITALIC,
};
DECLARE_ENUM_FLAG_OPERATORS (CellStyle)
}
#endif

@ -0,0 +1,15 @@
#ifndef __NCPP_NCALIGN_HH
#define __NCPP_NCALIGN_HH
#include <notcurses.h>
namespace ncpp
{
enum class NCAlign
{
Left = NCALIGN_LEFT,
Center = NCALIGN_CENTER,
Right = NCALIGN_RIGHT,
};
}
#endif

@ -0,0 +1,24 @@
#ifndef __NCPP_NCBOX_HH
#define __NCPP_NCBOX_HH
#include <notcurses.h>
namespace ncpp
{
struct NCBox
{
static constexpr unsigned MaskTop = NCBOXMASK_TOP;
static constexpr unsigned MaskRight = NCBOXMASK_RIGHT;
static constexpr unsigned MaskBottom = NCBOXMASK_BOTTOM;
static constexpr unsigned MaskLeft = NCBOXMASK_LEFT;
static constexpr unsigned GradTop = NCBOXGRAD_TOP;
static constexpr unsigned GradRight = NCBOXGRAD_RIGHT;
static constexpr unsigned GradBottom = NCBOXGRAD_BOTTOM;
static constexpr unsigned GradLeft = NCBOXGRAD_LEFT;
static constexpr unsigned CornerMask = NCBOXCORNER_MASK;
static constexpr unsigned CornerShift = NCBOXCORNER_SHIFT;
};
}
#endif

@ -0,0 +1,124 @@
#ifndef __NCPP_NCKEY_HH
#define __NCPP_NCKEY_HH
#include <cstdint>
#include <notcurses.h>
namespace ncpp
{
struct NCKey
{
static constexpr char32_t Invalid = NCKEY_INVALID;
static constexpr char32_t Resize = NCKEY_RESIZE;
static constexpr char32_t Up = NCKEY_UP;
static constexpr char32_t Right = NCKEY_RIGHT;
static constexpr char32_t Down = NCKEY_DOWN;
static constexpr char32_t Left = NCKEY_LEFT;
static constexpr char32_t Ins = NCKEY_INS;
static constexpr char32_t Del = NCKEY_DEL;
static constexpr char32_t Backspace = NCKEY_BACKSPACE;
static constexpr char32_t PgDown = NCKEY_PGDOWN;
static constexpr char32_t PgUp = NCKEY_PGUP;
static constexpr char32_t Home = NCKEY_HOME;
static constexpr char32_t End = NCKEY_END;
static constexpr char32_t F00 = NCKEY_F00;
static constexpr char32_t F01 = NCKEY_F01;
static constexpr char32_t F02 = NCKEY_F02;
static constexpr char32_t F03 = NCKEY_F03;
static constexpr char32_t F04 = NCKEY_F04;
static constexpr char32_t F05 = NCKEY_F05;
static constexpr char32_t F06 = NCKEY_F06;
static constexpr char32_t F07 = NCKEY_F07;
static constexpr char32_t F08 = NCKEY_F08;
static constexpr char32_t F09 = NCKEY_F09;
static constexpr char32_t F10 = NCKEY_F10;
static constexpr char32_t F11 = NCKEY_F11;
static constexpr char32_t F12 = NCKEY_F12;
static constexpr char32_t F13 = NCKEY_F13;
static constexpr char32_t F14 = NCKEY_F14;
static constexpr char32_t F15 = NCKEY_F15;
static constexpr char32_t F16 = NCKEY_F16;
static constexpr char32_t F17 = NCKEY_F17;
static constexpr char32_t F18 = NCKEY_F18;
static constexpr char32_t F19 = NCKEY_F19;
static constexpr char32_t F20 = NCKEY_F20;
static constexpr char32_t F21 = NCKEY_F21;
static constexpr char32_t F22 = NCKEY_F22;
static constexpr char32_t F23 = NCKEY_F23;
static constexpr char32_t F24 = NCKEY_F24;
static constexpr char32_t F25 = NCKEY_F25;
static constexpr char32_t F26 = NCKEY_F26;
static constexpr char32_t F27 = NCKEY_F27;
static constexpr char32_t F28 = NCKEY_F28;
static constexpr char32_t F29 = NCKEY_F29;
static constexpr char32_t F30 = NCKEY_F30;
static constexpr char32_t F31 = NCKEY_F31;
static constexpr char32_t F32 = NCKEY_F32;
static constexpr char32_t F33 = NCKEY_F33;
static constexpr char32_t F34 = NCKEY_F34;
static constexpr char32_t F35 = NCKEY_F35;
static constexpr char32_t F36 = NCKEY_F36;
static constexpr char32_t F37 = NCKEY_F37;
static constexpr char32_t F38 = NCKEY_F38;
static constexpr char32_t F39 = NCKEY_F39;
static constexpr char32_t F40 = NCKEY_F40;
static constexpr char32_t F41 = NCKEY_F41;
static constexpr char32_t F42 = NCKEY_F42;
static constexpr char32_t F43 = NCKEY_F43;
static constexpr char32_t F44 = NCKEY_F44;
static constexpr char32_t F45 = NCKEY_F45;
static constexpr char32_t F46 = NCKEY_F46;
static constexpr char32_t F47 = NCKEY_F47;
static constexpr char32_t F48 = NCKEY_F48;
static constexpr char32_t F49 = NCKEY_F49;
static constexpr char32_t F50 = NCKEY_F50;
static constexpr char32_t F51 = NCKEY_F51;
static constexpr char32_t F52 = NCKEY_F52;
static constexpr char32_t F53 = NCKEY_F53;
static constexpr char32_t F54 = NCKEY_F54;
static constexpr char32_t F55 = NCKEY_F55;
static constexpr char32_t F56 = NCKEY_F56;
static constexpr char32_t F57 = NCKEY_F57;
static constexpr char32_t F58 = NCKEY_F58;
static constexpr char32_t F59 = NCKEY_F59;
static constexpr char32_t F60 = NCKEY_F60;
static constexpr char32_t Enter = NCKEY_ENTER;
static constexpr char32_t CLS = NCKEY_CLS;
static constexpr char32_t DLeft = NCKEY_DLEFT;
static constexpr char32_t DRight = NCKEY_DRIGHT;
static constexpr char32_t ULeft = NCKEY_ULEFT;
static constexpr char32_t URight = NCKEY_URIGHT;
static constexpr char32_t Center = NCKEY_CENTER;
static constexpr char32_t Begin = NCKEY_BEGIN;
static constexpr char32_t Cancel = NCKEY_CANCEL;
static constexpr char32_t Close = NCKEY_CLOSE;
static constexpr char32_t Command = NCKEY_COMMAND;
static constexpr char32_t Copy = NCKEY_COPY;
static constexpr char32_t Exit = NCKEY_EXIT;
static constexpr char32_t Print = NCKEY_PRINT;
static constexpr char32_t Refresh = NCKEY_REFRESH;
static constexpr char32_t Button1 = NCKEY_BUTTON1;
static constexpr char32_t Button2 = NCKEY_BUTTON2;
static constexpr char32_t Button3 = NCKEY_BUTTON3;
static constexpr char32_t Button4 = NCKEY_BUTTON4;
static constexpr char32_t Button5 = NCKEY_BUTTON5;
static constexpr char32_t Button6 = NCKEY_BUTTON6;
static constexpr char32_t Button7 = NCKEY_BUTTON7;
static constexpr char32_t Button8 = NCKEY_BUTTON8;
static constexpr char32_t Button9 = NCKEY_BUTTON9;
static constexpr char32_t Button10 = NCKEY_BUTTON10;
static constexpr char32_t Button11 = NCKEY_BUTTON11;
static constexpr char32_t Release = NCKEY_RELEASE;
static bool IsMouse (char32_t ch) noexcept
{
return nckey_mouse_p (ch);
}
static bool IsSuppUAB (char32_t ch) noexcept
{
return nckey_supppuab_p (ch);
}
};
}
#endif

@ -0,0 +1,21 @@
#ifndef __NCPP_NCLOGLEVEL_HH
#define __NCPP_NCLOGLEVEL_HH
#include <notcurses.h>
namespace ncpp
{
struct NCLogLevel
{
static constexpr ncloglevel_e Silent = NCLOGLEVEL_SILENT;
static constexpr ncloglevel_e Panic = NCLOGLEVEL_PANIC;
static constexpr ncloglevel_e Fatal = NCLOGLEVEL_FATAL;
static constexpr ncloglevel_e Error = NCLOGLEVEL_ERROR;
static constexpr ncloglevel_e Warning = NCLOGLEVEL_WARNING;
static constexpr ncloglevel_e Info = NCLOGLEVEL_INFO;
static constexpr ncloglevel_e Verbose = NCLOGLEVEL_VERBOSE;
static constexpr ncloglevel_e Debug = NCLOGLEVEL_DEBUG;
static constexpr ncloglevel_e Trace = NCLOGLEVEL_TRACE;
};
}
#endif

@ -0,0 +1,15 @@
#ifndef __NCPP_NCSCALE_HH
#define __NCPP_NCSCALE_HH
#include <notcurses.h>
namespace ncpp
{
enum class NCScale
{
None = NCSCALE_NONE,
Scale = NCSCALE_SCALE,
Stretch = NCSCALE_STRETCH,
};
}
#endif

@ -0,0 +1,233 @@
#ifndef __NCPP_NOTCURSES_HH
#define __NCPP_NOTCURSES_HH
#include <cstdio>
#include <ctime>
#include <csignal>
#include <mutex>
#include <notcurses.h>
#include "CellStyle.hh"
#include "NCKey.hh"
#include "NCLogLevel.hh"
#include "Palette256.hh"
#include "Plane.hh"
#include "Root.hh"
#include "_helpers.hh"
namespace ncpp
{
class NCPP_API_EXPORT NotCurses : public Root
{
public:
static notcurses_options default_notcurses_options;
public:
explicit NotCurses (FILE *fp = nullptr)
: NotCurses (default_notcurses_options, fp)
{}
explicit NotCurses (const notcurses_options &nc_opts, FILE *fp = nullptr);
// Must not move or copy a NotCurses instance because we have no way to guarantee validity of any other copy
// when even a single instance is destructed as that operation would close not curses.
NotCurses (const NotCurses &other) = delete;
NotCurses (NotCurses &&other) = delete;
~NotCurses ()
{
if (nc == nullptr)
return;
notcurses_stop (nc);
}
operator notcurses* () noexcept
{
return nc;
}
operator notcurses const* () const noexcept
{
return nc;
}
static NotCurses& get_instance ()
{
if (_instance == nullptr)
throw new invalid_state_error ("NotCurses instance not found.");
if (_instance->nc == nullptr)
throw new invalid_state_error (ncpp_invalid_state_message);
return *_instance;
}
static bool is_notcurses_stopped ()
{
return *_instance == nullptr || _instance->nc == nullptr;
}
static const char* enmetric (uintmax_t val, unsigned decimal, char *buf, int omitdec, unsigned mult, int uprefix) noexcept
{
return ::enmetric (val, decimal, buf, omitdec, mult, uprefix);
}
static const char* qprefix (uintmax_t val, unsigned decimal, char *buf, int omitdec) noexcept
{
return ::qprefix (val, decimal, buf, omitdec);
}
static const char* bprefix (uintmax_t val, unsigned decimal, char *buf, int omitdec) noexcept
{
return ::bprefix (val, decimal, buf, omitdec);
}
static const char* version () noexcept
{
return notcurses_version ();
}
// This is potentially dangerous, but alas necessary. It can cause other calls here to fail in a bad way, but we
// need a way to report errors to std{out,err} in case of failure and that will work only if notcurses is
// stopped, so...
//
bool stop ()
{
if (nc == nullptr)
throw new invalid_state_error (ncpp_invalid_state_message);
notcurses_stop (nc);
nc = nullptr;
return true;
}
bool can_fade () const noexcept
{
return notcurses_canfade (nc);
}
bool can_open () const noexcept
{
return notcurses_canopen (nc);
}
bool can_change_color () const noexcept
{
return notcurses_canchangecolor (nc);
}
void get_stats (ncstats *stats) const noexcept
{
if (stats == nullptr)
return;
notcurses_stats (nc, stats);
}
void reset_stats (ncstats *stats) const
{
if (stats == nullptr)
throw new invalid_argument ("'stats' must be a valid pointer");
notcurses_reset_stats (nc, stats);
}
bool use (const Palette256 *p) const
{
if (p == nullptr)
throw new invalid_argument ("'p' must be a valid pointer");
return use (*p);
}
bool use (const Palette256 &p) const noexcept
{
return palette256_use (nc, reinterpret_cast<const palette256*>(&p)) != -1;
}
bool render () const noexcept
{
return notcurses_render (nc) == 0;
}
bool resize (int *rows, int *cols) const noexcept
{
return notcurses_resize (nc, rows, cols) == 0;
}
bool resize (int &rows, int &cols) const noexcept
{
return resize (&rows, &cols) == 0;
}
void get_term_dim (int *rows, int *cols) const noexcept
{
notcurses_term_dim_yx (nc, rows, cols);
}
void get_term_dim (int &rows, int &cols) const noexcept
{
get_term_dim (&rows, &cols);
}
bool refresh () const noexcept
{
return notcurses_refresh (nc) == 0;
}
int get_palette_size () const noexcept
{
return notcurses_palette_size (static_cast<const notcurses*> (nc));
}
bool mouse_enable () const noexcept
{
return notcurses_mouse_enable (nc) != -1;
}
bool mouse_disable () const noexcept
{
return notcurses_mouse_disable (nc) != -1;
}
CellStyle get_supported_styles () const noexcept
{
return static_cast<CellStyle>(notcurses_supported_styles (nc));
}
char32_t getc (const timespec *ts, sigset_t *sigmask = nullptr, ncinput *ni = nullptr) const noexcept
{
return notcurses_getc (nc, ts, sigmask, ni);
}
char32_t getc (bool blocking = false, ncinput *ni = nullptr) const noexcept
{
if (blocking)
return notcurses_getc_blocking (nc, ni);
return notcurses_getc_nblock (nc, ni);
}
char* get_at (int yoff, int xoff, Cell &c) const noexcept
{
return notcurses_at_yx (nc, yoff, xoff, c);
}
Plane* get_stdplane () noexcept
{
return new Plane (notcurses_stdplane (nc), true);
}
Plane* get_top () noexcept;
private:
notcurses *nc;
static NotCurses *_instance;
static std::mutex init_mutex;
};
}
#endif

@ -0,0 +1,65 @@
#ifndef __NCPP_PALETTE256_HH
#define __NCPP_PALETTE256_HH
#include "Root.hh"
#include "_helpers.hh"
namespace ncpp
{
class NCPP_API_EXPORT Palette256 : public Root
{
public:
Palette256 ()
{
palette = palette256_new (get_notcurses ());
if (palette == nullptr)
throw new init_error ("notcurses failed to create a new palette");
}
~Palette256 ()
{
palette256_free (palette);
}
operator palette256* () noexcept
{
return palette;
}
operator palette256 const* () const noexcept
{
return palette;
}
bool set (int idx, int r, int g, int b) const noexcept
{
return palette256_set_rgb (palette, idx, r, g, b) != -1;
}
bool set (int idx, unsigned rgb) const noexcept
{
return palette256_set (palette, idx, rgb) != -1;
}
bool get (int idx, unsigned *r, unsigned *g, unsigned *b) const
{
if (r == nullptr)
throw new invalid_argument ("'r' must be a valid pointer");
if (g == nullptr)
throw new invalid_argument ("'g' must be a valid pointer");
if (b == nullptr)
throw new invalid_argument ("'b' must be a valid pointer");
return get (idx, *r, *g, *b);
}
bool get (int idx, unsigned &r, unsigned &g, unsigned &b) const noexcept
{
return palette256_get_rgb (palette, idx, &r, &g, &b) != -1;
}
private:
palette256 *palette;
};
}
#endif

@ -0,0 +1,157 @@
#ifndef __NCPP_PANEL_REEL_HH
#define __NCPP_PANEL_REEL_HH
#include <memory>
#include <notcurses.h>
#include "Tablet.hh"
#include "Root.hh"
namespace ncpp
{
class Plane;
class NCPP_API_EXPORT PanelReel : public Root
{
public:
static panelreel_options default_options;
explicit PanelReel (Plane *plane, const panelreel_options *popts, int efd)
{
if (plane == nullptr)
throw new invalid_argument ("'plane' must be a valid pointer");
create_reel (reinterpret_cast<ncplane*>(plane), popts, efd);
}
explicit PanelReel (ncplane *plane, const panelreel_options *popts, int efd)
{
if (plane == nullptr)
throw new invalid_argument ("'plane' must be a valid pointer");
create_reel (plane, popts, efd);
}
~PanelReel ()
{
if (!is_notcurses_stopped ())
panelreel_destroy (reel);
}
operator panelreel* () const noexcept
{
return reel;
}
operator panelreel const* () const noexcept
{
return reel;
}
// TODO: add an overload using callback that takes Tablet instance instead of struct tablet
Tablet* add (Tablet *after, Tablet *before, tabletcb cb, void *opaque = nullptr) const
{
tablet *t = panelreel_add (reel, get_tablet (after), get_tablet (before), cb, opaque);
if (t == nullptr)
throw new init_error ("notcurses failed to create a new tablet");
return Tablet::map_tablet (t);
}
Tablet* add (Tablet &after, Tablet &before, tabletcb cb, void *opaque = nullptr) const noexcept
{
return add (&after, &before, cb, opaque);
}
int get_tabletcount () const noexcept
{
return panelreel_tabletcount (reel);
}
bool touch (Tablet *t) const noexcept
{
return panelreel_touch (reel, get_tablet (t)) != -1;
}
bool touch (Tablet &t) const noexcept
{
return touch (&t);
}
bool del (Tablet *t) const noexcept
{
return panelreel_del (reel, get_tablet (t)) != -1;
}
bool del (Tablet &t) const noexcept
{
return del (&t);
}
bool del_focused () const noexcept
{
return panelreel_del_focused (reel) != -1;
}
bool move (int x, int y) const noexcept
{
return panelreel_move (reel, x, y) != -1;
}
bool redraw () const noexcept
{
return panelreel_redraw (reel) != -1;
}
Tablet* get_focused () const noexcept
{
tablet *t = panelreel_focused (reel);
if (t == nullptr)
return nullptr;
return Tablet::map_tablet (t);
}
Tablet* next () const noexcept
{
tablet *t = panelreel_next (reel);
if (t == nullptr)
return nullptr;
return Tablet::map_tablet (t);
}
Tablet* prev () const noexcept
{
tablet *t = panelreel_prev (reel);
if (t == nullptr)
return nullptr;
return Tablet::map_tablet (t);
}
Plane* get_plane () const noexcept;
private:
tablet* get_tablet (Tablet *t) const noexcept
{
if (t == nullptr)
return nullptr;
return t->get_tablet ();
}
void create_reel (ncplane *plane, const panelreel_options *popts, int efd)
{
reel = panelreel_create (plane, popts == nullptr ? &default_options : popts, efd);
if (reel == nullptr)
throw new init_error ("notcurses failed to create a new panelreel");
}
private:
panelreel *reel = nullptr;
friend class Plane;
};
}
#endif

@ -0,0 +1,861 @@
#ifndef __NCPP_PLANE_HH
#define __NCPP_PLANE_HH
#include <exception>
#include <cstdarg>
#include <ctime>
#include <map>
#include <mutex>
#include <notcurses.h>
#include "Root.hh"
#include "Cell.hh"
#include "Visual.hh"
#include "PanelReel.hh"
#include "CellStyle.hh"
#include "NCAlign.hh"
#include "NCBox.hh"
namespace ncpp
{
class NCPP_API_EXPORT Plane : public Root
{
public:
explicit Plane (int rows, int cols, int yoff, int xoff, void *opaque = nullptr)
{
plane = ncplane_new (
get_notcurses (),
rows,
cols,
yoff,
xoff,
opaque
);
if (plane == nullptr)
throw new init_error ("notcurses failed to create a new plane");
map_plane (plane, this);
}
explicit Plane (Plane &n, int rows, int cols, int yoff, NCAlign align, void *opaque = nullptr)
{
plane = create_plane (n, rows, cols, yoff, align, opaque);
}
explicit Plane (Plane const& n, int rows, int cols, int yoff, NCAlign align, void *opaque = nullptr)
{
plane = create_plane (const_cast<Plane&>(n), rows, cols, yoff, align, opaque);
}
explicit Plane (Plane *n, int rows, int cols, int yoff, NCAlign align, void *opaque = nullptr)
{
if (n == nullptr)
throw new invalid_argument ("'n' must be a valid pointer");
plane = create_plane (*n, rows, cols, yoff, align, opaque);
}
explicit Plane (Plane const* n, int rows, int cols, int yoff, NCAlign align, void *opaque = nullptr)
{
if (n == nullptr)
throw new invalid_argument ("'n' must be a valid pointer");
plane = create_plane (const_cast<Plane&>(*n), rows, cols, yoff, align, opaque);
}
explicit Plane (ncplane *_plane) noexcept
: plane (_plane)
{}
~Plane () noexcept
{
if (is_stdplane)
return;
if (!is_notcurses_stopped ())
ncplane_destroy (plane);
unmap_plane (this);
}
operator ncplane* () noexcept
{
return plane;
}
operator ncplane const* () const noexcept
{
return plane;
}
bool resize (int keepy, int keepx, int keepleny, int keeplenx, int yoff, int xoff, int ylen, int xlen) const noexcept
{
return ncplane_resize (
plane,
keepy,
keepx,
keepleny,
keeplenx,
yoff,
xoff,
ylen,
xlen
) != -1;
}
bool pulse (const timespec* ts, fadecb fader, void* curry) const noexcept
{
return ncplane_pulse (plane, ts, fader, curry) != -1;
}
void greyscale () const noexcept
{
ncplane_greyscale (plane);
}
bool resize (int ylen, int xlen) const noexcept
{
return ncplane_resize_simple (plane, ylen, xlen) != -1;
}
bool fadeout (timespec *ts, fadecb fader = nullptr, void *curry = nullptr) const noexcept
{
return fadeout (static_cast<const timespec*>(ts), fader, curry);
}
bool fadeout (timespec &ts, fadecb fader = nullptr, void *curry = nullptr) const noexcept
{
return fadeout (&ts, fader, curry);
}
bool fadeout (timespec const& ts, fadecb fader = nullptr, void *curry = nullptr) const noexcept
{
return fadeout (&ts, fader, curry);
}
bool fadeout (const timespec *ts, fadecb fader = nullptr, void *curry = nullptr) const noexcept
{
return ncplane_fadeout (plane, ts, fader, curry) != -1;
}
bool fadein (timespec *ts, fadecb fader = nullptr) const noexcept
{
return fadein (static_cast<const timespec*>(ts), fader);
}
bool fadein (timespec &ts, fadecb fader = nullptr) const noexcept
{
return fadein (&ts, fader);
}
bool fadein (timespec const& ts, fadecb fader = nullptr) const noexcept
{
return fadein (&ts, fader);
}
bool fadein (const timespec *ts, fadecb fader = nullptr, void *curry = nullptr) const noexcept
{
return ncplane_fadein (plane, ts, fader, curry) != -1;
}
void erase () const noexcept
{
ncplane_erase (plane);
}
int get_align (NCAlign align, int c) const noexcept
{
return ncplane_align (plane, static_cast<ncalign_e>(align), c);
}
void get_dim (int *rows, int *cols) const noexcept
{
ncplane_dim_yx (plane, rows, cols);
}
void get_dim (int &rows, int &cols) const noexcept
{
get_dim (&rows, &cols);
}
int get_dim_x () const noexcept
{
return ncplane_dim_x (plane);
}
int get_dim_y () const noexcept
{
return ncplane_dim_y (plane);
}
void get_yx (int *y, int *x) const noexcept
{
ncplane_yx (plane, y, x);
}
void get_yx (int &y, int &x) const noexcept
{
get_yx (&y, &x);
}
bool move (int y, int x) const noexcept
{
return ncplane_move_yx (plane, y, x) != -1;
}
bool move_top () const noexcept
{
return ncplane_move_top (plane) != -1;
}
bool move_bottom () const noexcept
{
return ncplane_move_bottom (plane) != -1;
}
bool move_below (Plane &below) const noexcept
{
return ncplane_move_below (plane, below.plane) != -1;
}
bool move_below (Plane *below) const
{
if (below == nullptr)
throw new invalid_argument ("'below' must be a valid pointer");
return move_below (*below);
}
bool move_below_unsafe (Plane &below) const noexcept
{
return ncplane_move_below_unsafe (plane, below.plane) != -1;
}
bool move_below_unsafe (Plane *below) const
{
if (below == nullptr)
throw new invalid_argument ("'below' must be a valid pointer");
return move_below_unsafe (*below);
}
bool move_above (Plane &above) const noexcept
{
return ncplane_move_above (plane, above.plane) != -1;
}
bool move_above (Plane *above) const
{
if (above == nullptr)
throw new invalid_argument ("'above' must be a valid pointer");
return move_above (*above);
}
bool move_above_unsafe (Plane &above) const noexcept
{
return ncplane_move_above_unsafe (plane, above.plane) != -1;
}
bool move_above_unsafe (Plane *above) const
{
if (above == nullptr)
throw new invalid_argument ("'above' must be a valid pointer");
return move_above (*above);
}
bool cursor_move (int y, int x) const noexcept
{
return ncplane_cursor_move_yx (plane, y, x) != -1;
}
void get_cursor_yx (int *y, int *x) const noexcept
{
ncplane_cursor_yx (plane, y, x);
}
void get_cursor_yx (int &y, int &x) const noexcept
{
get_cursor_yx (&y, &x);
}
int putc (const Cell &c) const noexcept
{
return ncplane_putc (plane, c);
}
int putc (const Cell *c) const
{
if (c == nullptr)
throw new invalid_argument ("'c' must be a valid pointer");
return putc (*c);
}
int putc (int y, int x, Cell const& c) const noexcept
{
return ncplane_putc_yx (plane, y, x, c);
}
int putc (int y, int x, Cell const* c) const noexcept
{
if (c == nullptr)
return -1;
return putc (y, x, *c);
}
int putc (char c) const noexcept
{
return ncplane_putsimple (plane, c);
}
int putc (int y, int x, char c) const noexcept
{
return ncplane_putsimple_yx (plane, y, x, c);
}
int putc (const char *gclust, int *sbytes = nullptr) const noexcept
{
return ncplane_putegc (plane, gclust, sbytes);
}
int putc (int y, int x, const char *gclust, int *sbytes = nullptr) const noexcept
{
return ncplane_putegc_yx (plane, y, x, gclust, sbytes);
}
int putc (const wchar_t *gclust, int *sbytes = nullptr) const noexcept
{
return ncplane_putwegc (plane, gclust, sbytes);
}
int putc (int y, int x, const wchar_t *gclust, int *sbytes = nullptr) const noexcept
{
return ncplane_putwegc_yx (plane, y, x, gclust, sbytes);
}
// OK, this is ugly, but we need to rename this overload or calls similar to n->putc (0, 0, '0') will be
// considered ambiguous with the above `putc (int, int, char)` overload.
int putcw (int y, int x, wchar_t w) const noexcept
{
return ncplane_putwc_yx (plane, y, x, w);
}
// Ditto
int putcw (wchar_t w) const noexcept
{
return ncplane_putwc (plane, w);
}
int putstr (const char *gclustarr) const noexcept
{
return ncplane_putstr (plane, gclustarr);
}
int putstr (int y, int x, const char *gclustarr) const noexcept
{
return ncplane_putstr_yx (plane, y, x, gclustarr);
}
int putstr (int y, NCAlign atype, const char *s) const noexcept
{
return ncplane_putstr_aligned (plane, y, static_cast<ncalign_e>(atype), s);
}
int putstr (const wchar_t *gclustarr) const noexcept
{
return ncplane_putwstr (plane, gclustarr);
}
int putstr (int y, int x, const wchar_t *gclustarr) const noexcept
{
return ncplane_putwstr_yx (plane, y, x, gclustarr);
}
int putstr (int y, NCAlign atype, const wchar_t *gclustattr) const noexcept
{
return ncplane_putwstr_aligned (plane, y, static_cast<ncalign_e>(atype), gclustattr);
}
int printf (const char* format, ...) const noexcept
__attribute__ ((format (printf, 2, 3)))
{
va_list va;
va_start (va, format);
int ret = ncplane_vprintf (plane, format, va);
va_end (va);
return ret;
}
int printf (int y, int x, const char *format, ...) const noexcept
__attribute__ ((format (printf, 4, 5)))
{
va_list va;
va_start (va, format);
int ret = ncplane_vprintf_yx (plane, y, x, format, va);
va_end (va);
return ret;
}
int printf (int y, NCAlign align, const char *format, ...) const noexcept
__attribute__ ((format (printf, 4, 5)))
{
va_list va;
va_start (va, format);
int ret = vprintf (y, align, format, va);
va_end (va);
return ret;
}
int vprintf (const char* format, va_list ap) const noexcept
{
return ncplane_vprintf (plane, format, ap);
}
int vprintf (int y, int x, const char* format, va_list ap) const noexcept
{
return ncplane_vprintf_yx (plane, y, x, format, ap);
}
int vprintf (int y, NCAlign align, const char *format, va_list ap) const noexcept
{
return ncplane_vprintf_aligned (plane, y, static_cast<ncalign_e>(align), format, ap);
}
int hline (const Cell &c, int len) const noexcept
{
return ncplane_hline (plane, c, len);
}
int hline (const Cell &c, int len, uint64_t c1, uint64_t c2) const noexcept
{
return ncplane_hline_interp (plane, c, len, c1, c2);
}
int vline (const Cell &c, int len) const noexcept
{
return ncplane_vline (plane, c, len);
}
int vline (const Cell &c, int len, uint64_t c1, uint64_t c2) const noexcept
{
return ncplane_vline_interp (plane, c, len, c1, c2);
}
bool load_box (uint32_t attrs, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl, const char *gclusters) const noexcept
{
return cells_load_box (plane, attrs, channels, ul, ur, ll, lr, hl, vl, gclusters) != -1;
}
bool load_box (CellStyle style, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl, const char *gclusters) const noexcept
{
return load_box (static_cast<uint32_t>(style), channels, ul, ur, ll, lr, hl, vl, gclusters);
}
bool load_rounded_box (uint32_t attr, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const noexcept
{
return cells_rounded_box (plane, attr, channels, ul, ur, ll, lr, hl, vl) != -1;
}
bool load_rounded_box (CellStyle style, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const noexcept
{
return load_rounded_box (static_cast<uint32_t>(style), channels, ul, ur, ll, lr, hl, vl);
}
bool load_double_box (uint32_t attr, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const noexcept
{
return cells_double_box (plane, attr, channels, ul, ur, ll, lr, hl, vl) != -1;
}
bool load_double_box (CellStyle style, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const noexcept
{
return load_double_box (static_cast<uint32_t>(style), channels, ul, ur, ll, lr, hl, vl);
}
bool box (const Cell &ul, const Cell &ur, const Cell &ll, const Cell &lr,
const Cell &hline, const Cell &vline, int ystop, int xstop,
unsigned ctlword) const noexcept
{
return ncplane_box (plane, ul, ur, ll, lr, hline, vline, ystop, xstop, ctlword) != -1;
}
bool box_sized (const Cell &ul, const Cell &ur, const Cell &ll, const Cell &lr,
const Cell &hline, const Cell &vline, int ylen, int xlen,
unsigned ctlword) const noexcept
{
return ncplane_box_sized (plane, ul, ur, ll, lr, hline, vline, ylen, xlen, ctlword) != -1;
}
bool rounded_box (uint32_t attr, uint64_t channels, int ystop, int xstop, unsigned ctlword) const noexcept
{
return ncplane_rounded_box (plane, attr, channels, ystop, xstop, ctlword) != -1;
}
bool rounded_box_sized (uint32_t attr, uint64_t channels, int ylen, int xlen, unsigned ctlword) const noexcept
{
return ncplane_rounded_box_sized (plane, attr, channels, ylen, xlen, ctlword) != -1;
}
bool double_box (uint32_t attr, uint64_t channels, int ystop, int xstop, unsigned ctlword) const noexcept
{
return ncplane_double_box (plane, attr, channels, ystop, xstop, ctlword) != -1;
}
bool double_box_sized (uint32_t attr, uint64_t channels, int ylen, int xlen, unsigned ctlword) const noexcept
{
return ncplane_double_box_sized (plane, attr, channels, ylen, xlen, ctlword) != -1;
}
uint64_t get_channels () const noexcept
{
return ncplane_channels (plane);
}
uint32_t get_attr () const noexcept
{
return ncplane_attr (plane);
}
unsigned get_bchannel () const noexcept
{
return ncplane_bchannel (plane);
}
unsigned get_fchannel () const noexcept
{
return ncplane_fchannel (plane);
}
unsigned get_fg () const noexcept
{
return ncplane_fg (plane);
}
unsigned get_bg () const noexcept
{
return ncplane_bg (plane);
}
unsigned get_fg_alpha () const noexcept
{
return ncplane_fg_alpha (plane);
}
bool set_fg_alpha (int alpha) const noexcept
{
return ncplane_set_fg_alpha (plane, alpha) != -1;
}
unsigned get_bg_alpha () const noexcept
{
return ncplane_bg_alpha (plane);
}
bool set_bg_alpha (int alpha) const noexcept
{
return ncplane_set_bg_alpha (plane, alpha) != -1;
}
unsigned get_fg_rgb (unsigned *r, unsigned *g, unsigned *b) const noexcept
{
return ncplane_fg_rgb (plane, r, g, b);
}
bool set_fg_rgb (int r, int g, int b, bool clipped = false) const noexcept
{
if (clipped) {
ncplane_set_fg_rgb_clipped (plane, r, g, b);
return true;
}
return ncplane_set_fg_rgb (plane, r, g, b) != -1;
}
bool set_fg_palindex (int idx) const noexcept
{
return ncplane_set_fg_palindex (plane, idx) != -1;
}
bool set_fg (uint32_t channel) const noexcept
{
return ncplane_set_fg (plane, channel) != -1;
}
void set_fg_default () const noexcept
{
ncplane_set_fg_default (plane);
}
unsigned get_bg_rgb (unsigned *r, unsigned *g, unsigned *b) const noexcept
{
return ncplane_bg_rgb (plane, r, g, b);
}
bool set_bg_rgb (int r, int g, int b, bool clipped = false) const noexcept
{
if (clipped) {
ncplane_set_fg_rgb_clipped (plane, r, g, b);
return true;
}
return ncplane_set_bg_rgb (plane, r, g, b) != -1;
}
bool set_bg_palindex (int idx) const noexcept
{
return ncplane_set_bg_alpha (plane, idx) != -1;
}
bool set_bg (uint32_t channel) const noexcept
{
return ncplane_set_bg (plane, channel) != -1;
}
void set_bg_default () const noexcept
{
ncplane_set_bg_default (plane);
}
void styles_set (CellStyle styles) const noexcept
{
ncplane_styles_set (plane, static_cast<unsigned>(styles));
}
void styles_on (CellStyle styles) const noexcept
{
ncplane_styles_on (plane, static_cast<unsigned>(styles));
}
void styles_off (CellStyle styles) const noexcept
{
ncplane_styles_off (plane, static_cast<unsigned>(styles));
}
Plane* get_below () const noexcept
{
return map_plane (ncplane_below (plane));
}
bool set_base (Cell &c) const noexcept
{
return ncplane_set_base (plane, c) >= 0;
}
bool get_base (Cell &c) const noexcept
{
return ncplane_base (plane, c) >= 0;
}
bool at_cursor (Cell &c) const noexcept
{
return ncplane_at_cursor (plane, c) >= 0;
}
bool at_cursor (Cell *c) const
{
if (c == nullptr)
return false;
return at_cursor (*c);
}
int get_at (int y, int x, Cell &c) const noexcept
{
return ncplane_at_yx (plane, y, x, c);
}
int get_at (int y, int x, Cell *c) const
{
if (c == nullptr)
return -1;
return get_at (y, x, *c);
}
void* set_userptr (void *opaque) const noexcept
{
return ncplane_set_userptr (plane, opaque);
}
template<typename T>
T* set_userptr (T *opaque) const noexcept
{
return static_cast<T*>(set_userptr (static_cast<void*>(opaque)));
}
void* get_userptr () const noexcept
{
return ncplane_userptr (plane);
}
template<typename T>
T* get_userptr () const noexcept
{
return static_cast<T*>(get_userptr ());
}
Visual* visual_open (const char *file, int *averr) const
{
return new Visual (plane, file, averr);
}
PanelReel* panelreel_create (const panelreel_options *popts = nullptr, int efd = -1) const
{
return new PanelReel (plane, popts, efd);
}
// Some Cell APIs go here since they act on individual panels even though it may seem weird at points (e.g.
// release)
int load (Cell &cell, const char *gcluster) const noexcept
{
return cell_load (plane, cell, gcluster);
}
bool load (Cell &cell, char ch) const noexcept
{
return cell_load_simple (plane, cell, ch) != -1;
}
int prime (Cell &cell, const char *gcluster, uint32_t attr, uint64_t channels) const noexcept
{
return cell_prime (plane, cell, gcluster, attr, channels);
}
void release (Cell &cell) const noexcept
{
cell_release (plane, cell);
}
int duplicate (Cell &target, Cell &source) const noexcept
{
return cell_duplicate (plane, target, source);
}
int duplicate (Cell &target, Cell const& source) const noexcept
{
return cell_duplicate (plane, target, source);
}
int duplicate (Cell &target, Cell *source) const
{
if (source == nullptr)
throw new invalid_argument ("'source' must be a valid pointer");
return duplicate (target, *source);
}
int duplicate (Cell &target, Cell const* source) const
{
if (source == nullptr)
throw new invalid_argument ("'source' must be a valid pointer");
return duplicate (target, *source);
}
int duplicate (Cell *target, Cell *source) const
{
if (target == nullptr)
throw new invalid_argument ("'target' must be a valid pointer");
if (source == nullptr)
throw new invalid_argument ("'source' must be a valid pointer");
return duplicate (*target, *source);
}
int duplicate (Cell *target, Cell const* source) const
{
if (target == nullptr)
throw new invalid_argument ("'target' must be a valid pointer");
if (source == nullptr)
throw new invalid_argument ("'source' must be a valid pointer");
return duplicate (*target, *source);
}
int duplicate (Cell *target, Cell &source) const
{
if (target == nullptr)
throw new invalid_argument ("'target' must be a valid pointer");
return duplicate (*target, source);
}
int duplicate (Cell *target, Cell const& source) const
{
if (target == nullptr)
throw new invalid_argument ("'target' must be a valid pointer");
return duplicate (*target, source);
}
// Upstream call doesn't take ncplane* but we put it here for parity with has_no_background below
bool has_no_foreground (Cell &cell) const noexcept
{
return cell.has_no_foreground ();
}
const char* get_extended_gcluster (Cell &cell) const noexcept
{
return cell_extended_gcluster (plane, cell);
}
const char* get_extended_gcluster (Cell const& cell) const noexcept
{
return cell_extended_gcluster (plane, cell);
}
static Plane* map_plane (ncplane *ncp, Plane *associated_plane = nullptr) noexcept;
protected:
explicit Plane (ncplane *_plane, bool _is_stdplane)
: plane (_plane),
is_stdplane (_is_stdplane)
{
if (_plane == nullptr)
throw new invalid_argument ("_plane must be a valid pointer");
}
static void unmap_plane (Plane *p) noexcept;
private:
ncplane* create_plane (Plane &n, int rows, int cols, int yoff, NCAlign align, void *opaque)
{
ncplane *ret = ncplane_aligned (
n.plane,
rows,
cols,
yoff,
static_cast<ncalign_e>(align),
opaque
);
if (ret == nullptr)
throw new init_error ("notcurses failed to create an aligned plane");
map_plane (plane, this);
return ret;
}
private:
ncplane *plane = nullptr;
bool is_stdplane = false;
static std::map<ncplane*,Plane*> *plane_map;
static std::mutex plane_map_mutex;
friend class NotCurses;
friend class Visual;
friend class PanelReel;
friend class Tablet;
};
}
#endif

@ -0,0 +1,25 @@
#ifndef __NCPP_ROOT_HH
#define __NCPP_ROOT_HH
#include <notcurses.h>
#include "_helpers.hh"
#include "_exceptions.hh"
namespace ncpp {
class NCPP_API_EXPORT Root
{
protected:
static constexpr char ncpp_invalid_state_message[] = "notcurses++ is in an invalid state (already stopped?)";
protected:
notcurses* get_notcurses () const;
// All the objects which need to destroy notcurses entities (planes, panelreel etc etc) **have to** call this
// function before calling to notcurses from their destructor. This is to prevent a segfault when
// NotCurses::stop has been called and the app uses smart pointers holding NotCurses objects which may be
// destructed **after** notcurses is stopped.
bool is_notcurses_stopped () const noexcept;
};
}
#endif

@ -0,0 +1,61 @@
#ifndef __NCPP_TABLET_HH
#define __NCPP_TABLET_HH
#include <map>
#include <mutex>
#include <notcurses.h>
#include "Root.hh"
namespace ncpp
{
class Plane;
class NCPP_API_EXPORT Tablet : public Root
{
protected:
explicit Tablet (tablet *t)
: _tablet (t)
{
if (t == nullptr)
throw new invalid_argument ("'t' must be a valid pointer");
};
public:
template<typename T>
T* get_userptr () const noexcept
{
return static_cast<T*>(tablet_userptr (_tablet));
}
operator tablet* () const noexcept
{
return _tablet;
}
operator tablet const* () const noexcept
{
return _tablet;
}
Plane* get_plane () const noexcept;
static Tablet* map_tablet (tablet *t) noexcept;
protected:
static void unmap_tablet (Tablet *p) noexcept;
tablet* get_tablet () const noexcept
{
return _tablet;
}
private:
tablet *_tablet = nullptr;
static std::map<tablet*,Tablet*> *tablet_map;
static std::mutex tablet_map_mutex;
friend class PanelReel;
};
}
#endif

@ -0,0 +1,7 @@
#ifndef __NCPP_TABLET_CALLBACK_HH
#define __NCPP_TABLET_CALLBACK_HH
namespace ncpp
{
}
#endif

@ -0,0 +1,78 @@
#ifndef __NCPP_VISUAL_HH
#define __NCPP_VISUAL_HH
#include <notcurses.h>
#include "Root.hh"
#include "NCScale.hh"
namespace ncpp
{
class Plane;
class NCPP_API_EXPORT Visual : public Root
{
public:
explicit Visual (Plane *plane, const char *file, int *averr)
: Visual (reinterpret_cast<ncplane*>(plane), file, averr)
{}
explicit Visual (ncplane *plane, const char *file, int *averr)
{
if (plane == nullptr)
throw new invalid_argument ("'plane' must be a valid pointer");
visual = ncplane_visual_open (reinterpret_cast<ncplane*>(plane), file, averr);
if (visual == nullptr)
throw new init_error ("notcurses failed to create a new visual");
}
explicit Visual (const char *file, int *averr, int y, int x, NCScale scale)
{
visual = ncvisual_open_plane (get_notcurses (), file, averr, y, x, static_cast<ncscale_e>(scale));
if (visual == nullptr)
throw new init_error ("notcurses failed to create a new visual");
}
~Visual () noexcept
{
destroy_plane (get_plane ());
if (!is_notcurses_stopped ())
ncvisual_destroy (visual);
}
operator ncvisual* () const noexcept
{
return visual;
}
operator ncvisual const* () const noexcept
{
return visual;
}
AVFrame* decode (int *averr) const noexcept
{
return ncvisual_decode (visual, averr);
}
bool render (int begy, int begx, int leny, int lenx) const noexcept
{
return ncvisual_render (visual, begy, begx, leny, lenx) != -1;
}
int stream (int *averr, float timescale, streamcb streamer, void *curry = nullptr) const noexcept
{
return ncvisual_stream (get_notcurses (), visual, averr, timescale, streamer, curry);
}
Plane* get_plane () const noexcept;
private:
static void destroy_plane (Plane *plane) noexcept;
private:
ncvisual *visual = nullptr;
};
}
#endif

@ -0,0 +1,46 @@
#ifndef __NCPP_EXCEPTIONS_HH
#define __NCPP_EXCEPTIONS_HH
#include <stdexcept>
#include "_helpers.hh"
namespace ncpp
{
class NCPP_API_EXPORT init_error : public std::logic_error
{
public:
explicit init_error (const std::string& what_arg)
: logic_error (what_arg)
{}
explicit init_error (const char* what_arg)
: logic_error (what_arg)
{}
};
class NCPP_API_EXPORT invalid_state_error : public std::logic_error
{
public:
explicit invalid_state_error (const std::string& what_arg)
: logic_error (what_arg)
{}
explicit invalid_state_error (const char* what_arg)
: logic_error (what_arg)
{}
};
class NCPP_API_EXPORT invalid_argument : public std::invalid_argument
{
public:
explicit invalid_argument (const std::string& what_arg)
: std::invalid_argument (what_arg)
{}
explicit invalid_argument (const char* what_arg)
: std::invalid_argument (what_arg)
{}
};
}
#endif

@ -0,0 +1,52 @@
#ifndef __NCPP_FLAG_ENUM_OPERATOR_HELPERS_H
#define __NCPP_FLAG_ENUM_OPERATOR_HELPERS_H
#include <type_traits>
#include "_helpers.hh"
namespace ncpp
{
#define DECLARE_ENUM_FLAG_OPERATORS(__enum_name__) \
NCPP_API_EXPORT constexpr __enum_name__ operator& (__enum_name__ x, __enum_name__ y) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return __enum_name__ (static_cast<etype> (x) & static_cast<etype> (y)); \
} \
NCPP_API_EXPORT constexpr __enum_name__& operator&= (__enum_name__& x, __enum_name__ y) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return x = __enum_name__ (static_cast<etype> (x) & static_cast<etype> (y)); \
} \
NCPP_API_EXPORT constexpr __enum_name__ operator| (__enum_name__ x, __enum_name__ y) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return __enum_name__ (static_cast<etype> (x) | static_cast<etype> (y)); \
} \
NCPP_API_EXPORT constexpr __enum_name__& operator|= (__enum_name__& x, __enum_name__ y) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return x = __enum_name__ (static_cast<etype> (x) | static_cast<etype> (y)); \
} \
NCPP_API_EXPORT constexpr __enum_name__ operator^ (__enum_name__ x, __enum_name__ y) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return __enum_name__ (static_cast<etype> (x) ^ static_cast<etype> (y)); \
} \
NCPP_API_EXPORT constexpr __enum_name__& operator^= (__enum_name__& x, __enum_name__ y) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return x = __enum_name__ (static_cast<etype> (x) ^ static_cast<etype> (y)); \
} \
NCPP_API_EXPORT constexpr __enum_name__& operator~ (__enum_name__& x) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return x = __enum_name__ (~static_cast<etype> (x)); \
} \
NCPP_API_EXPORT constexpr __enum_name__ operator~ (__enum_name__ x) \
{ \
typedef std::underlying_type<__enum_name__>::type etype; \
return __enum_name__ (~static_cast<etype> (x)); \
}
}
#endif

@ -0,0 +1,12 @@
#ifndef __NCPP_HELPERS_HH
#define __NCPP_HELPERS_HH
namespace ncpp
{
#define NCPP_LIKELY(expr) (__builtin_expect ((expr) != 0, 1))
#define NCPP_UNLIKELY(expr) (__builtin_expect ((expr) != 0, 0))
#define NCPP_API_EXPORT __attribute__((visibility ("default")))
#define NCPP_API_LOCAL __attribute__((visibility ("hidden")))
}
#endif

@ -0,0 +1,47 @@
#ifndef __NCPP_INTERNAL_HELPERS_HH
#define __NCPP_INTERNAL_HELPERS_HH
#include <functional>
#include <map>
#include <mutex>
namespace ncpp::internal
{
class Helpers
{
public:
template<typename TKey, typename TValue>
static TValue lookup_map_entry (std::map<TKey,TValue> *&_map, std::mutex &_mutex, TKey _key, std::function<TValue (TKey)> create_value)
{
std::lock_guard<std::mutex> lock (_mutex);
if (_map == nullptr) {
_map = new std::map<TKey,TValue> ();
}
TValue ret;
auto entry = _map->find (_key);
if (entry == _map->end ()) {
ret = create_value (_key);
} else {
ret = entry->second;
}
return ret;
}
template<typename TKey, typename TValue>
static void remove_map_entry (std::map<TKey,TValue> *&_map, std::mutex &_mutex, TKey _key)
{
std::lock_guard<std::mutex> lock (_mutex);
if (_map == nullptr)
return;
auto entry = _map->find (_key);
if (entry == _map->end ())
return;
_map->erase (entry);
}
};
}
#endif

@ -0,0 +1,12 @@
#ifndef __NCPP_NCPP_HH
#define __NCPP_NCPP_HH
#include <notcurses.h>
#include "NotCurses.hh"
namespace ncpp
{
}
#endif

@ -5,16 +5,20 @@
#include <clocale>
#include <iostream>
#include <termios.h>
#include <notcurses.h>
#include <memory>
#include <ncpp/NotCurses.hh>
#include <ncpp/Plane.hh>
using namespace ncpp;
static int dimy, dimx;
static struct notcurses* nc;
// return the string version of a special composed key
const char* nckeystr(char32_t spkey){
switch(spkey){ // FIXME
case NCKEY_RESIZE:
notcurses_resize(nc, &dimy, &dimx);
NotCurses::get_instance ().resize(&dimy, &dimx);
return "resize event";
case NCKEY_INVALID: return "invalid";
case NCKEY_LEFT: return "left";
@ -129,112 +133,107 @@ char32_t printutf8(char32_t kp){
// Dim all text on the plane by the same amount. This will stack for
// older text, and thus clearly indicate the current output.
static int
dim_rows(struct ncplane* n){
static bool
dim_rows(std::shared_ptr<Plane> n){
int y, x;
cell c = CELL_TRIVIAL_INITIALIZER;
Cell c;
for(y = 2 ; y < dimy ; ++y){
for(x = 0 ; x < dimx ; ++x){
if(ncplane_at_yx(n, y, x, &c) < 0){
cell_release(n, &c);
return -1;
if(n->get_at(y, x, &c) < 0){
n->release(c);
return false;
}
unsigned r, g, b;
cell_fg_rgb(&c, &r, &g, &b);
c.get_fg_rgb(&r, &g, &b);
r -= r / 32;
g -= g / 32;
b -= b / 32;
if(r > 247){ r = 0; }
if(g > 247){ g = 0; }
if(b > 247){ b = 0; }
if(cell_set_fg_rgb(&c, r, g, b)){
cell_release(n, &c);
return -1;
if(!c.set_fg_rgb(r, g, b)){
n->release(c);
return false;
}
if(ncplane_putc_yx(n, y, x, &c) < 0){
cell_release(n, &c);
return -1;
if(n->putc(y, x, c) < 0){
n->release(c);
return false;
}
if(cell_double_wide_p(&c)){
if(c.is_double_wide()){
++x;
}
}
}
cell_release(n, &c);
return 0;
n->release(c);
return true;
}
int main(void){
if(setlocale(LC_ALL, "") == nullptr){
return EXIT_FAILURE;
}
notcurses_options opts{};
opts.clear_screen_start = true;
if((nc = notcurses_init(&opts, stdout)) == nullptr){
return EXIT_FAILURE;;
}
if(notcurses_mouse_enable(nc)){
notcurses_stop(nc);
NotCurses::default_notcurses_options.clear_screen_start = true;
NotCurses nc;
if(!nc.mouse_enable ()){
return EXIT_FAILURE;
}
struct ncplane* n = notcurses_stdplane(nc);
notcurses_term_dim_yx(nc, &dimy, &dimx);
ncplane_set_fg(n, 0);
ncplane_set_bg(n, 0xbb64bb);
ncplane_styles_on(n, CELL_STYLE_UNDERLINE);
if(ncplane_putstr_aligned(n, 0, NCALIGN_CENTER, "mash keys, yo. give that mouse some waggle! ctrl+d exits.") <= 0){
notcurses_stop(nc);
std::shared_ptr<Plane> n(nc.get_stdplane ());
nc.get_term_dim(&dimy, &dimx);
n->set_fg(0);
n->set_bg(0xbb64bb);
n->styles_on(CellStyle::Underline);
if(n->putstr(0, NCAlign::Center, "mash keys, yo. give that mouse some waggle! ctrl+d exits.") <= 0){
return EXIT_FAILURE;
}
ncplane_styles_set(n, 0);
ncplane_set_bg_default(n);
notcurses_render(nc);
n->styles_set(CellStyle::None);
n->set_bg_default();
nc.render();
int y = 2;
std::deque<wchar_t> cells;
char32_t r;
ncinput ni;
while(errno = 0, (r = notcurses_getc_blocking(nc, &ni)) != (char32_t)-1){
while(errno = 0, (r = nc.getc(true, &ni)) != (char32_t)-1){
if(r == 0){ // interrupted by signal
continue;
}
if((r == 'D' || r == 'd') && ni.ctrl){
notcurses_stop(nc);
return EXIT_SUCCESS;
}
if(ncplane_cursor_move_yx(n, y, 0)){
if(!n->cursor_move(y, 0)){
break;
}
ncplane_set_fg_rgb(n, 0xd0, 0xd0, 0xd0);
ncplane_printf(n, "%c%c%c ", ni.alt ? 'A' : 'a', ni.ctrl ? 'C' : 'c',
ni.shift ? 'S' : 's');
n->set_fg_rgb(0xd0, 0xd0, 0xd0);
n->printf("%c%c%c ", ni.alt ? 'A' : 'a', ni.ctrl ? 'C' : 'c',
ni.shift ? 'S' : 's');
if(r < 0x80){
ncplane_set_fg_rgb(n, 128, 250, 64);
if(ncplane_printf(n, "ASCII: [0x%02x (%03d)] '%lc'",
r, r, iswprint(r) ? r : printutf8(r)) < 0){
n->set_fg_rgb(128, 250, 64);
if(n->printf("ASCII: [0x%02x (%03d)] '%lc'",
r, r, iswprint(r) ? r : printutf8(r)) < 0){
break;
}
}else{
if(nckey_supppuab_p(r)){
ncplane_set_fg_rgb(n, 250, 64, 128);
if(ncplane_printf(n, "Special: [0x%02x (%02d)] '%s'",
r, r, nckeystr(r)) < 0){
n->set_fg_rgb(250, 64, 128);
if(n->printf("Special: [0x%02x (%02d)] '%s'",
r, r, nckeystr(r)) < 0){
break;
}
if(nckey_mouse_p(r)){
if(ncplane_printf_aligned(n, -1, NCALIGN_RIGHT, " x: %d y: %d",
ni.x, ni.y) < 0){
if(NCKey::IsMouse(r)){
if(n->printf(-1, NCAlign::Right, " x: %d y: %d",
ni.x, ni.y) < 0){
break;
}
}
}else{
ncplane_set_fg_rgb(n, 64, 128, 250);
ncplane_printf(n, "Unicode: [0x%08x] '%lc'", r, r);
n->set_fg_rgb(64, 128, 250);
n->printf("Unicode: [0x%08x] '%lc'", r, r);
}
}
if(dim_rows(n)){
if(!dim_rows(n)){
break;
}
if(notcurses_render(nc)){
if(!nc.render()){
break;
}
if(++y >= dimy - 2){ // leave a blank line at the bottom
@ -246,7 +245,7 @@ int main(void){
cells.push_front(r);
}
int e = errno;
notcurses_stop(nc);
nc.stop();
if(r == (char32_t)-1 && e){
std::cerr << "Error reading from terminal (" << strerror(e) << "?)\n";
}

@ -0,0 +1,41 @@
#include <ncpp/NotCurses.hh>
#include <ncpp/NCLogLevel.hh>
using namespace ncpp;
notcurses_options NotCurses::default_notcurses_options = {
/* termtype */ nullptr,
/* inhibit_alternate_screen */ false,
/* retain_cursor */ false,
/* clear_screen_start */ false,
/* suppress_bannner */ false,
/* no_quit_sighandlers */ false,
/* no_winch_sighandler */ false,
/* renderfp */ nullptr,
/* loglevel */ NCLogLevel::Silent,
};
NotCurses *NotCurses::_instance = nullptr;
std::mutex NotCurses::init_mutex;
NotCurses::NotCurses (const notcurses_options &nc_opts, FILE *fp)
{
const std::lock_guard<std::mutex> lock (init_mutex);
if (_instance != nullptr)
throw new init_error ("There can be only one instance of the NotCurses class. Use NotCurses::get_instance() to access the existing instance.");
nc = notcurses_init (&nc_opts, fp == nullptr ? stdout : fp);
if (nc == nullptr)
throw new init_error ("notcurses failed to initialize");
_instance = this;
}
Plane* NotCurses::get_top () noexcept
{
ncplane *top = notcurses_top (nc);
if (top == nullptr)
return nullptr;
return Plane::map_plane (top);
}

@ -0,0 +1,29 @@
#include <ncpp/Plane.hh>
#include <ncpp/PanelReel.hh>
#include <ncpp/NCBox.hh>
using namespace ncpp;
panelreel_options PanelReel::default_options = {
/* min_supported_cols */ 0,
/* min_supported_rows */ 0,
/* max_supported_cols */ 0,
/* max_supported_rows */ 0,
/* toff */ 0,
/* roff */ 0,
/* boff */ 0,
/* loff */ 0,
/* infinitescroll */ false,
/* circular */ false,
/* bordermask */ NCBox::MaskBottom | NCBox::MaskTop | NCBox::MaskRight | NCBox::MaskLeft,
/* borderchan */ 0,
/* tabletmask */ 0,
/* tabletchan */ 0,
/* focusedchan */ 0,
/* bgchannel */ 0,
};
Plane* PanelReel::get_plane () const noexcept
{
return Plane::map_plane (panelreel_plane (reel));
}

@ -0,0 +1,30 @@
#include <ncpp/Plane.hh>
#include <ncpp/internal/Helpers.hh>
using namespace ncpp;
std::map<ncplane*,Plane*> *Plane::plane_map = nullptr;
std::mutex Plane::plane_map_mutex;
Plane* Plane::map_plane (ncplane *ncp, Plane *associated_plane) noexcept
{
if (ncp == nullptr)
return nullptr;
return internal::Helpers::lookup_map_entry <ncplane*, Plane*> (
plane_map,
plane_map_mutex,
ncp,
[&] (ncplane *_ncp) -> Plane* {
return associated_plane == nullptr ? new Plane (_ncp) : associated_plane;
}
);
}
void Plane::unmap_plane (Plane *p) noexcept
{
if (p == nullptr)
return;
internal::Helpers::remove_map_entry (plane_map, plane_map_mutex, p->plane);
}

@ -0,0 +1,17 @@
#include <ncpp/Root.hh>
#include <ncpp/NotCurses.hh>
using namespace ncpp;
notcurses* Root::get_notcurses () const
{
notcurses *ret = NotCurses::get_instance ();
if (ret == nullptr)
throw new invalid_state_error (ncpp_invalid_state_message);
return ret;
}
bool Root::is_notcurses_stopped () const noexcept
{
return NotCurses::is_notcurses_stopped ();
}

@ -0,0 +1,36 @@
#include <ncpp/Plane.hh>
#include <ncpp/Tablet.hh>
#include <ncpp/internal/Helpers.hh>
using namespace ncpp;
std::map<tablet*,Tablet*> *Tablet::tablet_map = nullptr;
std::mutex Tablet::tablet_map_mutex;
Tablet* Tablet::map_tablet (tablet *t) noexcept
{
if (t == nullptr)
return nullptr;
return internal::Helpers::lookup_map_entry <tablet*, Tablet*> (
tablet_map,
tablet_map_mutex,
t,
[&] (tablet *_t) -> Tablet* {
return new Tablet (_t);
}
);
}
void Tablet::unmap_tablet (Tablet *p) noexcept
{
if (p == nullptr)
return;
internal::Helpers::remove_map_entry (tablet_map, tablet_map_mutex, p->_tablet);
}
Plane* Tablet::get_plane () const noexcept
{
return Plane::map_plane (tablet_ncplane (_tablet));
}

@ -0,0 +1,14 @@
#include <ncpp/Visual.hh>
#include <ncpp/Plane.hh>
using namespace ncpp;
Plane* Visual::get_plane () const noexcept
{
return Plane::map_plane (ncvisual_plane (visual));
}
void Visual::destroy_plane (Plane *plane) noexcept
{
delete plane;
}

@ -3,10 +3,12 @@
#include <sstream>
#include <getopt.h>
#include <iostream>
#include <notcurses.h>
#include <memory>
#include <ncpp/NotCurses.hh>
#include <ncpp/PanelReel.hh>
#include <ncpp/NCKey.hh>
// FIXME ought be able to get pr from tablet, methinks?
static struct panelreel* PR;
using namespace ncpp;
class TabletCtx {
public:
@ -18,15 +20,16 @@ class TabletCtx {
int lines;
};
int tabletfxn(struct tablet* t, int begx, int begy, int maxx, int maxy,
int tabletfxn(struct tablet* _t, int begx, int begy, int maxx, int maxy,
bool cliptop){
struct ncplane* p = tablet_ncplane(t);
TabletCtx *tctx = (TabletCtx*)tablet_userptr(t);
ncplane_erase(p);
cell c = CELL_SIMPLE_INITIALIZER(' ');
cell_set_bg(&c, (((uintptr_t)t) % 0x1000000) + cliptop + begx + maxx);
ncplane_set_base(p, &c);
cell_release(p, &c);
Tablet *t = Tablet::map_tablet (_t);
Plane* p = t->get_plane();
auto tctx = t->get_userptr<TabletCtx>();
p->erase();
Cell c(' ');
c.set_bg((((uintptr_t)t) % 0x1000000) + cliptop + begx + maxx);
p->set_base(c);
p->release(c);
return tctx->getLines() > maxy - begy ? maxy - begy : tctx->getLines();
}
@ -105,64 +108,53 @@ int main(int argc, char** argv){
if(setlocale(LC_ALL, "") == nullptr){
return EXIT_FAILURE;
}
struct notcurses_options opts{};
struct panelreel_options popts{};
parse_args(argc, argv, &opts, &popts);
struct notcurses* nc = notcurses_init(&opts, stdout);
if(!nc){
return EXIT_FAILURE;
}
struct ncplane* nstd = notcurses_stdplane(nc);
parse_args(argc, argv, &NotCurses::default_notcurses_options, &PanelReel::default_options);
NotCurses nc;
std::unique_ptr<Plane> nstd(nc.get_stdplane());
int dimy, dimx;
ncplane_dim_yx(nstd, &dimy, &dimx);
struct ncplane* n = ncplane_new(nc, dimy - 1, dimx, 1, 0, nullptr);
nstd->get_dim(&dimy, &dimx);
auto n = std::make_shared<Plane>(dimy - 1, dimx, 1, 0);
if(!n){
notcurses_stop(nc);
return EXIT_FAILURE;
}
if(ncplane_set_fg(nstd, 0xb11bb1)){
notcurses_stop(nc);
if(!nstd->set_fg(0xb11bb1)){
return EXIT_FAILURE;
}
if(ncplane_putstr_aligned(nstd, 0, NCALIGN_CENTER, "(a)dd (d)el (q)uit") <= 0){
notcurses_stop(nc);
if(nstd->putstr(0, NCAlign::Center, "(a)dd (d)el (q)uit") <= 0){
return EXIT_FAILURE;
}
channels_set_fg(&popts.focusedchan, 0xffffff);
channels_set_bg(&popts.focusedchan, 0x00c080);
channels_set_fg(&popts.borderchan, 0x00c080);
struct panelreel* pr = panelreel_create(n, &popts, -1);
if(!pr || notcurses_render(nc)){
notcurses_stop(nc);
channels_set_fg(&PanelReel::default_options.focusedchan, 0xffffff);
channels_set_bg(&PanelReel::default_options.focusedchan, 0x00c080);
channels_set_fg(&PanelReel::default_options.borderchan, 0x00c080);
std::shared_ptr<PanelReel> pr(n->panelreel_create());
if(!pr || !nc.render()){
return EXIT_FAILURE;
}
PR = pr; // FIXME eliminate
char32_t key;
while((key = notcurses_getc_blocking(nc, nullptr)) != (char32_t)-1){
while((key = nc.getc(true)) != (char32_t)-1){
switch(key){
case 'q':
return notcurses_stop(nc) ? EXIT_FAILURE : EXIT_SUCCESS;
return !nc.stop() ? EXIT_FAILURE : EXIT_SUCCESS;
case 'a':{
TabletCtx* tctx = new TabletCtx();
panelreel_add(pr, nullptr, nullptr, tabletfxn, tctx);
pr->add(nullptr, nullptr, tabletfxn, tctx);
break;
}
case 'd':
panelreel_del_focused(pr);
pr->del_focused();
break;
case NCKEY_UP:
panelreel_prev(pr);
pr->prev();
break;
case NCKEY_DOWN:
panelreel_next(pr);
pr->next();
break;
default:
break;
}
if(notcurses_render(nc)){
if(!nc.render()){
break;
}
}
notcurses_stop(nc);
return EXIT_FAILURE;
}

@ -2,52 +2,49 @@
#include <cstdlib>
#include <clocale>
#include <cassert>
#include <memory>
#include <unistd.h>
#include <notcurses.h>
#include <ncpp/NotCurses.hh>
using namespace ncpp;
int main(int argc, char** argv){
setlocale(LC_ALL, "");
notcurses_options opts{};
opts.inhibit_alternate_screen = true;
struct notcurses* nc;
if((nc = notcurses_init(&opts, stdout)) == nullptr){
return EXIT_FAILURE;
}
struct ncplane* n = notcurses_stdplane(nc);
NotCurses::default_notcurses_options.inhibit_alternate_screen = true;
NotCurses nc;
std::unique_ptr<Plane> n (nc.get_stdplane());
int dimx, dimy;
ncplane_dim_yx(n, &dimy, &dimx);
nc.get_term_dim(&dimy, &dimx);
const int HEIGHT = 5;
const int WIDTH = 20;
struct ncplane* na = ncplane_aligned(n, HEIGHT, WIDTH,
dimy - (HEIGHT + 1),
NCALIGN_CENTER,
nullptr);
auto na = std::make_unique<Plane>(n.get(), HEIGHT, WIDTH,
dimy - (HEIGHT + 1),
NCAlign::Center);
uint64_t channels = 0;
if(na == nullptr){
if(!na){
goto err;
}
ncplane_set_fg(n, 0x00ff00);
ncplane_set_fg(na, 0x00ff00);
if(ncplane_cursor_move_yx(na, 0, 0)){
n->set_fg(0x00ff00);
na->set_fg(0x00ff00);
if(!na->cursor_move(0, 0)){
goto err;
}
if(ncplane_rounded_box_sized(na, 0, channels, HEIGHT, WIDTH, 0) < 0){
if(!na->rounded_box_sized(0, channels, HEIGHT, WIDTH, 0)){
goto err;
}
if(ncplane_printf_yx(n, 0, 0, "arrrrp?") < 0){
if(n->printf(0, 0, "arrrrp?") < 0){
goto err;
}
if(ncplane_rounded_box_sized(n, 4, channels, HEIGHT, WIDTH, 0) < 0){
if(!n->rounded_box_sized(4, channels, HEIGHT, WIDTH, 0)){
goto err;
}
if(notcurses_render(nc)){
if(!nc.render()){
goto err;
}
sleep(1);
return notcurses_stop(nc) ? EXIT_FAILURE : EXIT_SUCCESS;
return nc.stop() ? EXIT_FAILURE : EXIT_SUCCESS;
err:
notcurses_stop(nc);
return EXIT_FAILURE;
}

@ -1,27 +1,25 @@
#include <cstdlib>
#include <locale.h>
#include <clocale>
#include <memory>
#include <unistd.h>
#include <notcurses.h>
#include <ncpp/NotCurses.hh>
#include <ncpp/Plane.hh>
int mathtext(struct notcurses* nc){
int dimx, dimy;
notcurses_term_dim_yx(nc, &dimy, &dimx);
const int HEIGHT = 9;
const int WIDTH = dimx;
struct ncplane* n = ncplane_new(nc, HEIGHT, WIDTH, dimy - HEIGHT - 1, dimx - WIDTH - 1, NULL);
using namespace ncpp;
int mathtext([[maybe_unused]] NotCurses& nc, std::shared_ptr<Plane> n){
if(n){
struct ncplane* stdn = notcurses_stdplane(nc);
ncplane_set_fg(n, 0xffffff);
ncplane_set_bg(n, 0x008000);
ncplane_printf_aligned(n, 0, NCALIGN_RIGHT, "∮E⋅da=Q,n→∞,∑f(i)=∏g(i)⎧⎡⎛┌─────┐⎞⎤⎫");
ncplane_printf_aligned(n, 1, NCALIGN_RIGHT, "⎪⎢⎜│a²+b³ ⎟⎥⎪");
ncplane_printf_aligned(n, 2, NCALIGN_RIGHT, "∀x∈:⌈x⌉=x⌋,α∧¬β=¬(¬α∨β)⎪⎢⎜│───── ⎟⎥⎪");
ncplane_printf_aligned(n, 3, NCALIGN_RIGHT, "⎪⎢⎜⎷ c₈ ⎟⎥⎪");
ncplane_printf_aligned(n, 4, NCALIGN_RIGHT, "ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ(z̄=(z)(z)⋅𝑖)⎨⎢⎜ ⎟⎥⎬");
ncplane_printf_aligned(n, 5, NCALIGN_RIGHT, "⎪⎢⎜ ∞ ⎟⎥⎪");
ncplane_printf_aligned(n, 6, NCALIGN_RIGHT, "⊥<a≠b≡c≤d≪⇒(⟦A⟧⇔⟪B⟫)⎪⎢⎜ ⎲ ⎟⎥⎪");
ncplane_printf_aligned(n, 7, NCALIGN_RIGHT, "⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪");
ncplane_printf_aligned(n, 8, NCALIGN_RIGHT, "2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200µm⎩⎣⎝i=1 ⎠⎦⎭");
n->set_fg(0xffffff);
n->set_bg(0x008000);
n->printf(0, NCAlign::Right, "∮E⋅da=Q,n→∞,∑f(i)=∏g(i)⎧⎡⎛┌─────┐⎞⎤⎫");
n->printf(1, NCAlign::Right, "⎪⎢⎜│a²+b³ ⎟⎥⎪");
n->printf(2, NCAlign::Right, "∀x∈:⌈x⌉=x⌋,α∧¬β=¬(¬α∨β)⎪⎢⎜│───── ⎟⎥⎪");
n->printf(3, NCAlign::Right, "⎪⎢⎜⎷ c₈ ⎟⎥⎪");
n->printf(4, NCAlign::Right, "ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ(z̄=(z)(z)⋅𝑖)⎨⎢⎜ ⎟⎥⎬");
n->printf(5, NCAlign::Right, "⎪⎢⎜ ∞ ⎟⎥⎪");
n->printf(6, NCAlign::Right, "⊥<a≠b≡c≤d≪⇒(⟦A⟧⇔⟪B⟫)⎪⎢⎜ ⎲ ⎟⎥⎪");
n->printf(7, NCAlign::Right, "⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪");
n->printf(8, NCAlign::Right, "2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200µm⎩⎣⎝i=1 ⎠⎦⎭");
}
return 0;
}
@ -30,12 +28,9 @@ int main(void){
if(setlocale(LC_ALL, "") == nullptr){
return EXIT_FAILURE;
}
notcurses_options opts{};
opts.inhibit_alternate_screen = true;
struct notcurses* nc = notcurses_init(&opts, stdout);
if(nc == nullptr){
return EXIT_FAILURE;
}
NotCurses::default_notcurses_options.inhibit_alternate_screen = true;
NotCurses nc;
const char c[] =
"Jegkanspiseglassutenåskademeg"
"Egkannetaglasskaðaleysur"
@ -65,18 +60,19 @@ int main(void){
"Hikiiaʻukeʻaiikeaniani;ʻaʻolenōlāaueʻeha"
"Ekoʻanaekaiitekarahimeaʻāʻaʻehauhau"
"ᐊᓕᒍᖅᓂᕆᔭᕌᖓᒃᑯᓱᕋᙱᑦᑐᓐᓇᖅᑐ";
struct ncplane* n = notcurses_stdplane(nc);
int y, dimy;
notcurses_term_dim_yx(nc, &dimy, nullptr);
std::unique_ptr<Plane> nstd(nc.get_stdplane());
int y, dimy, dimx;
nc.get_term_dim(&dimy, &dimx);
do{
ncplane_putstr(n, c);
ncplane_cursor_yx(n, &y, nullptr);
nstd->putstr(c);
nstd->get_cursor_yx(&y, nullptr);
}while(y < dimy);
if(mathtext(nc)){
notcurses_stop(nc);
const int HEIGHT = 9;
const int WIDTH = dimx;
std::shared_ptr<Plane> n = std::make_shared<Plane>(HEIGHT, WIDTH, dimy - HEIGHT - 1, dimx - WIDTH - 1);
if(mathtext(nc, n)){
return EXIT_FAILURE;
}
notcurses_render(nc);
notcurses_stop(nc);
nc.render();
return 0;
}

@ -2,25 +2,25 @@
#include <cstdlib>
#include <clocale>
#include <cassert>
#include <notcurses.h>
#include <memory>
#include <ncpp/NotCurses.hh>
#include <ncpp/Plane.hh>
using namespace ncpp;
// What happens when we print over half of a wide glyph?
int main(int argc, char** argv){
setlocale(LC_ALL, "");
notcurses_options opts{};
opts.inhibit_alternate_screen = true;
struct notcurses* nc;
if((nc = notcurses_init(&opts, stdout)) == nullptr){
return EXIT_FAILURE;
}
struct ncplane* n = notcurses_stdplane(nc);
NotCurses::default_notcurses_options.inhibit_alternate_screen = true;
NotCurses nc;
std::shared_ptr<Plane> n(nc.get_stdplane());
int dimx, dimy;
ncplane_dim_yx(n, &dimy, &dimx);
cell c = CELL_TRIVIAL_INITIALIZER;
cell_set_bg_rgb(&c, 0, 0x80, 0);
//ncplane_set_default(n, &c);
if(cell_load(n, &c, "🐳") < 0){
n->get_dim(&dimy, &dimx);
Cell c;
c.set_bg_rgb(0, 0x80, 0);
//n->set_default(c);
if(n->load(c, "🐳") < 0){
goto err;
}
if(dimy > 5){
@ -28,20 +28,20 @@ int main(int argc, char** argv){
}
for(int i = 0 ; i < dimy ; ++i){
for(int j = 8 ; j < dimx / 2 ; ++j){ // leave some empty spaces
if(ncplane_putc_yx(n, i, j * 2, &c) < 0){
if(n->putc(i, j * 2, &c) < 0){
goto err;
}
}
}
ncplane_putc_yx(n, dimy, dimx - 3, &c);
ncplane_putc_yx(n, dimy, dimx - 1, &c);
ncplane_putc_yx(n, dimy + 1, dimx - 2, &c);
ncplane_putc_yx(n, dimy + 1, dimx - 4, &c);
cell_release(n, &c);
n->putc(dimy, dimx - 3, &c);
n->putc(dimy, dimx - 1, &c);
n->putc(dimy + 1, dimx - 2, &c);
n->putc(dimy + 1, dimx - 4, &c);
n->release(c);
// put these on the right side of the wide glyphs
for(int i = 0 ; i < dimy / 2 ; ++i){
for(int j = 5 ; j < dimx / 2 ; j += 2){
if(ncplane_putsimple_yx(n, i, j, (j % 10) + '0') < 0){
if(n->putc(i, j, (j % 10) + '0') < 0){
goto err;
}
}
@ -49,18 +49,17 @@ int main(int argc, char** argv){
// put these on the left side of the wide glyphs
for(int i = dimy / 2 ; i < dimy ; ++i){
for(int j = 4 ; j < dimx / 2 ; j += 2){
if(ncplane_putsimple_yx(n, i, j, (j % 10) + '0') < 0){
if(n->putc(i, j, (j % 10) + '0') < 0){
goto err;
}
}
}
if(notcurses_render(nc)){
if(!nc.render()){
goto err;
}
printf("\n");
return notcurses_stop(nc) ? EXIT_FAILURE : EXIT_SUCCESS;
return !nc.stop() ? EXIT_FAILURE : EXIT_SUCCESS;
err:
notcurses_stop(nc);
return EXIT_FAILURE;
}

@ -1,38 +1,42 @@
#include <cstdlib>
#include <clocale>
#include <unistd.h>
#include <notcurses.h>
#include <memory>
#include <ncpp/NotCurses.hh>
#include <ncpp/Plane.hh>
using namespace ncpp;
constexpr auto DELAY = 1;
// dump two wide glyphs, then create a new plane and drop it atop them
int stomper(struct notcurses* nc, struct ncplane* nn){
ncplane_move_yx(nn, 0, 1);
int stomper(NotCurses& nc, std::shared_ptr<Plane> nn){
nn->move(0, 1);
notcurses_render(nc);
nc.render();
sleep(DELAY);
// first wide glyph gone, second present
ncplane_move_yx(nn, 1, 0);
notcurses_render(nc);
nn->move(1, 0);
nc.render();
sleep(DELAY);
// second wide glyph gone, first present
ncplane_move_yx(nn, 2, 2);
notcurses_render(nc);
nn->move(2, 2);
nc.render();
sleep(DELAY);
ncplane_move_yx(nn, 4, 0);
notcurses_render(nc);
nn->move(4, 0);
nc.render();
sleep(DELAY);
ncplane_move_yx(nn, 5, 1);
notcurses_render(nc);
nn->move(5, 1);
nc.render();
sleep(DELAY);
ncplane_move_yx(nn, 6, 2);
notcurses_render(nc);
nn->move(6, 2);
nc.render();
sleep(DELAY);
return 0;
@ -40,36 +44,33 @@ int stomper(struct notcurses* nc, struct ncplane* nn){
int main(void){
setlocale(LC_ALL, "");
notcurses_options opts{};
struct notcurses* nc = notcurses_init(&opts, stdout);
struct ncplane* n = notcurses_stdplane(nc);
NotCurses nc;
std::shared_ptr<Plane> n(nc.get_stdplane());
// first, a 2x1 with "AB"
struct ncplane* nn = ncplane_new(nc, 1, 2, 1, 16, nullptr);
ncplane_set_fg_rgb(nn, 0xc0, 0x80, 0xc0);
ncplane_set_bg_rgb(nn, 0x20, 0x00, 0x20);
ncplane_putstr(nn, "AB");
ncplane_set_fg_rgb(n, 0x80, 0xc0, 0x80);
ncplane_set_bg_rgb(n, 0x00, 0x40, 0x00);
ncplane_putstr(n, "\xe5\xbd\xa2\xe5\x85\xa8");
ncplane_putstr_yx(n, 1, 0, "\xe5\xbd\xa2\xe5\x85\xa8");
ncplane_putstr_yx(n, 2, 0, "\xe5\xbd\xa2\xe5\x85\xa8");
ncplane_putstr_yx(n, 3, 0, "\xe5\xbd\xa2\xe5\x85\xa8");
ncplane_putstr_yx(n, 4, 0, "abcdef");
ncplane_putstr_yx(n, 5, 0, "abcdef");
ncplane_putstr_yx(n, 6, 0, "abcdef");
ncplane_putstr_yx(n, 7, 0, "abcdef");
notcurses_render(nc);
auto nn = std::make_shared<Plane>(1, 2, 1, 16);
nn->set_fg_rgb(0xc0, 0x80, 0xc0);
nn->set_bg_rgb(0x20, 0x00, 0x20);
nn->putstr("AB");
n->set_fg_rgb(0x80, 0xc0, 0x80);
n->set_bg_rgb(0x00, 0x40, 0x00);
n->putstr("\xe5\xbd\xa2\xe5\x85\xa8");
n->putstr(1, 0, "\xe5\xbd\xa2\xe5\x85\xa8");
n->putstr(2, 0, "\xe5\xbd\xa2\xe5\x85\xa8");
n->putstr(3, 0, "\xe5\xbd\xa2\xe5\x85\xa8");
n->putstr(4, 0, "abcdef");
n->putstr(5, 0, "abcdef");
n->putstr(6, 0, "abcdef");
n->putstr(7, 0, "abcdef");
nc.render();
sleep(1);
stomper(nc, nn);
if(ncplane_putstr_yx(nn, 0, 0, "\xe5\xbd\xa1") <= 0){
notcurses_stop(nc);
if(nn->putstr(0, 0, "\xe5\xbd\xa1") <= 0){
return EXIT_FAILURE;
}
stomper(nc, nn);
notcurses_stop(nc);
return EXIT_SUCCESS;
}

@ -7,7 +7,9 @@
#include <libgen.h>
#include <unistd.h>
#include <iostream>
#include "notcurses.h"
#include <memory>
#include <ncpp/NotCurses.hh>
#include <ncpp/Visual.hh>
extern "C" {
#include <libavutil/pixdesc.h>
@ -15,6 +17,8 @@ extern "C" {
#include <libavcodec/avcodec.h> // ffmpeg doesn't reliably "C"-guard itself
}
using namespace ncpp;
static void usage(std::ostream& os, const char* name, int exitcode)
__attribute__ ((noreturn));
@ -34,34 +38,35 @@ timespec_to_ns(const struct timespec* ts){
}
// frame count is in the curry. original time is in the ncplane's userptr.
int perframe(struct notcurses* nc, struct ncvisual* ncv, void* vframecount){
int perframe([[maybe_unused]] struct notcurses* _nc, struct ncvisual* ncv, void* vframecount){
NotCurses &nc = NotCurses::get_instance ();
struct timespec* start = static_cast<struct timespec*>(ncplane_userptr(ncvisual_plane(ncv)));
if(!start){
start = new struct timespec;
clock_gettime(CLOCK_MONOTONIC, start);
ncplane_set_userptr(ncvisual_plane(ncv), start);
}
struct ncplane* stdn = notcurses_stdplane(nc);
std::unique_ptr<Plane> stdn(nc.get_stdplane());
int* framecount = static_cast<int*>(vframecount);
++*framecount;
ncplane_set_fg(stdn, 0x80c080);
stdn->set_fg(0x80c080);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int64_t ns = timespec_to_ns(&now) - timespec_to_ns(start);
ncplane_printf_aligned(stdn, 0, NCALIGN_LEFT, "Got frame %05d\u2026", *framecount);
stdn->printf(0, NCAlign::Left, "Got frame %05d\u2026", *framecount);
const int64_t h = ns / (60 * 60 * NANOSECS_IN_SEC);
ns -= h * (60 * 60 * NANOSECS_IN_SEC);
const int64_t m = ns / (60 * NANOSECS_IN_SEC);
ns -= m * (60 * NANOSECS_IN_SEC);
const int64_t s = ns / NANOSECS_IN_SEC;
ns -= s * NANOSECS_IN_SEC;
ncplane_printf_aligned(stdn, 0, NCALIGN_RIGHT, "%02ld:%02ld:%02ld.%04ld",
h, m, s, ns / 1000000);
if(notcurses_render(nc)){
stdn->printf(0, NCAlign::Right, "%02ld:%02ld:%02ld.%04ld",
h, m, s, ns / 1000000);
if(!nc.render()){
return -1;
}
int dimx, dimy, oldx, oldy, keepy, keepx;
notcurses_term_dim_yx(nc, &dimy, &dimx);
nc.get_term_dim(&dimy, &dimx);
ncplane_dim_yx(ncvisual_plane(ncv), &oldy, &oldx);
keepy = oldy > dimy ? dimy : oldy;
keepx = oldx > dimx ? dimx : oldx;
@ -76,10 +81,10 @@ int perframe(struct notcurses* nc, struct ncvisual* ncv, void* vframecount){
}
// can exit() directly. returns index in argv of first non-option param.
int handle_opts(int argc, char** argv, notcurses_options* opts, float* timescale,
ncscale_e *scalemode) {
int handle_opts(int argc, char** argv, notcurses_options& opts, float* timescale,
NCScale* scalemode) {
*timescale = 1.0;
*scalemode = NCSCALE_SCALE;
*scalemode = NCScale::Scale;
int c;
while((c = getopt(argc, argv, "hl:d:s:")) != -1){
switch(c){
@ -88,11 +93,11 @@ int handle_opts(int argc, char** argv, notcurses_options* opts, float* timescale
break;
case 's':
if(strcmp(optarg, "stretch") == 0){
*scalemode = NCSCALE_STRETCH;
*scalemode = NCScale::Stretch;
}else if(strcmp(optarg, "scale") == 0){
*scalemode = NCSCALE_SCALE;
*scalemode = NCScale::Scale;
}else if(strcmp(optarg, "none") == 0){
*scalemode = NCSCALE_NONE;
*scalemode = NCScale::None;
}
break;
case 'd':{
@ -111,7 +116,7 @@ int handle_opts(int argc, char** argv, notcurses_options* opts, float* timescale
ss << optarg;
int ll;
ss >> ll;
if(ll < NCLOGLEVEL_SILENT || ll > NCLOGLEVEL_TRACE){
if(ll < NCLogLevel::Silent || ll > NCLogLevel::Trace){
std::cerr << "Invalid log level [" << optarg << "] (wanted [0..8])\n";
usage(std::cerr, argv[0], EXIT_FAILURE);
}
@ -119,7 +124,7 @@ int handle_opts(int argc, char** argv, notcurses_options* opts, float* timescale
std::cerr << "Invalid log level [" << optarg << "] (wanted [0..8])\n";
usage(std::cerr, argv[0], EXIT_FAILURE);
}
opts->loglevel = static_cast<ncloglevel_e>(ll);
opts.loglevel = static_cast<ncloglevel_e>(ll);
break;
}default:
usage(std::cerr, argv[0], EXIT_FAILURE);
@ -135,55 +140,48 @@ int handle_opts(int argc, char** argv, notcurses_options* opts, float* timescale
int main(int argc, char** argv){
setlocale(LC_ALL, "");
notcurses_options opts{};
float timescale;
ncscale_e stretchmode;
auto nonopt = handle_opts(argc, argv, &opts, &timescale, &stretchmode);
auto nc = notcurses_init(&opts, stdout);
if(nc == nullptr){
return EXIT_FAILURE;
}
NCScale stretchmode;
auto nonopt = handle_opts(argc, argv, NotCurses::default_notcurses_options, &timescale, &stretchmode);
NotCurses nc;
int dimy, dimx;
notcurses_term_dim_yx(nc, &dimy, &dimx);
nc.get_term_dim(&dimy, &dimx);
for(auto i = nonopt ; i < argc ; ++i){
std::array<char, 128> errbuf;
int frames = 0;
int averr;
auto ncv = ncvisual_open_plane(nc, argv[i], &averr, 1, 0, stretchmode);
if(ncv == nullptr){
auto ncv = std::make_unique<Visual>(argv[i], &averr, 1, 0, stretchmode);
if(!ncv){
av_make_error_string(errbuf.data(), errbuf.size(), averr);
notcurses_stop(nc);
nc.stop();
std::cerr << "Error opening " << argv[i] << ": " << errbuf.data() << std::endl;
return EXIT_FAILURE;
}
auto r = ncvisual_stream(nc, ncv, &averr, timescale, perframe, &frames);
int r = ncv->stream(&averr, timescale, perframe, &frames);
if(r < 0){ // positive is intentional abort
av_make_error_string(errbuf.data(), errbuf.size(), averr);
notcurses_stop(nc);
nc.stop();
std::cerr << "Error decoding " << argv[i] << ": " << errbuf.data() << std::endl;
return EXIT_FAILURE;
}else if(r == 0){
auto ie = notcurses_getc_blocking(nc, nullptr);
char32_t ie = nc.getc(true);
if(ie == (char32_t)-1){
break;
}else if(ie == 'q'){
break;
}else if(ie == NCKEY_RESIZE){
}else if(ie == NCKey::Resize){
--i; // rerun with the new size
if(notcurses_resize(nc, &dimy, &dimx)){
notcurses_stop(nc);
if(!nc.resize(&dimy, &dimx)){
return EXIT_FAILURE;
}
if(ncplane_resize_simple(ncvisual_plane(ncv), dimy, dimx)){
notcurses_stop(nc);
if(!ncv->get_plane ()->resize(dimy, dimx)){
nc.stop();
return EXIT_FAILURE;
}
}
}
delete static_cast<struct timespec*>(ncplane_userptr(ncvisual_plane(ncv)));
ncvisual_destroy(ncv);
}
if(notcurses_stop(nc)){
if(!nc.stop()){
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

@ -0,0 +1,12 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: @PROJECT_NAME@
Description: C++ bindings for notcurses
Version: @PROJECT_VERSION@
Requires: notcurses >= @PROJECT_VERSION@
Libs: -L${libdir} -lnotcurses++
Cflags: -I${includedir}
Loading…
Cancel
Save