├── .drone.yml ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── feature-request.md │ ├── problem-report.md │ └── question.md └── workflows │ ├── macos_test.yml │ ├── ubuntu_test.yml │ └── windows_test.yml ├── .gitignore ├── .vscode └── settings.json ├── CMakeLists.txt ├── CONTRIBUTING.md ├── COPYRIGHT ├── INSTALL.md ├── NEWS.md ├── README.md ├── TERMINALS.md ├── USAGE.md ├── cffi ├── .gitignore ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── ncdirect-pydemo ├── ncdirect-pydemo.1.md ├── notcurses-pydemo ├── notcurses-pydemo.1.md ├── setup.cfg ├── setup.py └── src │ └── notcurses │ ├── __init__.py │ ├── build_notcurses.py │ └── notcurses.py ├── data ├── PurpleDrank.jpg ├── Windows10Logo.png ├── aidsrobots.jpeg ├── atma.png ├── changes.jpg ├── changes.xcf ├── chunli01.png ├── chunli02.png ├── chunli03.png ├── chunli04.png ├── chunli05.png ├── chunli06.png ├── chunli07.png ├── chunli08.png ├── chunli09.png ├── chunli1.bmp ├── chunli10.png ├── chunli11.png ├── chunli12.png ├── chunli13.png ├── chunli14.png ├── chunli15.png ├── chunli16.png ├── chunli17.png ├── chunli18.png ├── chunli19.png ├── chunli2.bmp ├── chunli20.png ├── chunli21.png ├── chunli22.png ├── chunli23.png ├── chunli24.png ├── chunli25.png ├── chunli26.png ├── chunli27.png ├── chunli28.png ├── chunli29.png ├── chunli3.bmp ├── chunli30.png ├── chunli31.png ├── chunli32.png ├── chunli33.png ├── chunli34.png ├── chunli35.png ├── chunli36.png ├── chunli37.png ├── chunli38.png ├── chunli39.png ├── chunli4.bmp ├── chunli40.png ├── chunli41.png ├── chunli42.png ├── chunli43.png ├── chunli44.png ├── chunli45.png ├── chunli5.bmp ├── chunli6.bmp ├── chunli7.bmp ├── chunli8.bmp ├── covid19.jpg ├── dsscaw-purp.png ├── eagles.png ├── fm6.mov ├── fonts.jpg ├── freebsd.png ├── lamepatents.jpg ├── megaman2.bmp ├── natasha-blur.png ├── natasha-blur.xcf ├── normal.png ├── normal.xcf ├── notcurses.png ├── notcursesIII.mov ├── onedot.png ├── samoa.avi ├── samoa.osp ├── spaceship.png ├── tetris-background.jpg ├── tetris-background.xcf ├── warmech.bmp └── worldmap.png ├── doc ├── 0001-console-answer-OSC-10-and-11.patch ├── CURSES.md ├── Doxyfile ├── HACKING.md ├── HISTORY.md ├── OTHERS.md ├── analytics-header.html ├── examples │ ├── Makefile │ ├── book.toml │ └── src │ │ ├── SUMMARY.md │ │ ├── basics.md │ │ ├── boxes.md │ │ ├── colors.md │ │ ├── directmode-helloworld.c │ │ ├── directmode-helloworld.png │ │ ├── directmode.md │ │ ├── fdwidget.md │ │ ├── input.md │ │ ├── media.md │ │ ├── menus.md │ │ ├── planes.md │ │ ├── plots.md │ │ ├── reader.md │ │ ├── reels.md │ │ ├── rendered.md │ │ ├── selectors.md │ │ └── writetext.md ├── icon.ico ├── icon.png ├── logo-1280x640.png ├── logo-200x55.png ├── man │ ├── index.html │ ├── man1 │ │ ├── ncls.1.md │ │ ├── ncneofetch.1.md │ │ ├── ncplayer.1.md │ │ ├── nctetris.1.md │ │ ├── notcurses-demo.1.md │ │ ├── notcurses-info.1.md │ │ ├── notcurses-input.1.md │ │ ├── notcurses-tester.1.md │ │ └── tfman.1.md │ └── man3 │ │ ├── notcurses.3.md │ │ ├── notcurses_capabilities.3.md │ │ ├── notcurses_cell.3.md │ │ ├── notcurses_channels.3.md │ │ ├── notcurses_core.3.md │ │ ├── notcurses_direct.3.md │ │ ├── notcurses_fade.3.md │ │ ├── notcurses_fds.3.md │ │ ├── notcurses_init.3.md │ │ ├── notcurses_input.3.md │ │ ├── notcurses_lines.3.md │ │ ├── notcurses_menu.3.md │ │ ├── notcurses_metric.3.md │ │ ├── notcurses_multiselector.3.md │ │ ├── notcurses_output.3.md │ │ ├── notcurses_palette.3.md │ │ ├── notcurses_pile.3.md │ │ ├── notcurses_plane.3.md │ │ ├── notcurses_plot.3.md │ │ ├── notcurses_progbar.3.md │ │ ├── notcurses_reader.3.md │ │ ├── notcurses_reel.3.md │ │ ├── notcurses_refresh.3.md │ │ ├── notcurses_render.3.md │ │ ├── notcurses_selector.3.md │ │ ├── notcurses_stats.3.md │ │ ├── notcurses_stdplane.3.md │ │ ├── notcurses_stop.3.md │ │ ├── notcurses_tabbed.3.md │ │ ├── notcurses_tree.3.md │ │ ├── notcurses_util.3.md │ │ └── notcurses_visual.3.md ├── model.dot ├── proposed-terminfo.md ├── release-checklist.md ├── sexblitter-perfection.png ├── sexblitter-perfection.xcf ├── testing-checklist.md ├── worldmap-sexblitter.png └── worldmap-sexblitter.xcf ├── include ├── ncpp │ ├── Cell.hh │ ├── CellStyle.hh │ ├── Direct.hh │ ├── FDPlane.hh │ ├── Menu.hh │ ├── MultiSelector.hh │ ├── NCAlign.hh │ ├── NCBox.hh │ ├── NCKey.hh │ ├── NCLogLevel.hh │ ├── NotCurses.hh │ ├── Palette.hh │ ├── Pile.hh │ ├── Plane.hh │ ├── Plot.hh │ ├── Progbar.hh │ ├── Reader.hh │ ├── Reel.hh │ ├── Root.hh │ ├── Selector.hh │ ├── Subproc.hh │ ├── Tablet.hh │ ├── TabletCallback.hh │ ├── Utilities.hh │ ├── Visual.hh │ ├── Widget.hh │ ├── _exceptions.hh │ ├── _flag_enum_operator_helpers.hh │ ├── _helpers.hh │ ├── internal │ │ └── Helpers.hh │ └── ncpp.hh └── notcurses │ ├── direct.h │ ├── nckeys.h │ ├── ncport.h │ ├── ncseqs.h │ └── notcurses.h ├── python ├── .gitignore ├── .readthedocs.yml ├── CMakeLists.txt ├── HACKING.md ├── LICENSE ├── docs │ ├── conf.py │ ├── index.rst │ ├── nc_context.rst │ ├── nc_direct.rst │ ├── nc_input.rst │ ├── nc_misc.rst │ └── nc_plane.rst ├── examples │ ├── 000-print-version.py │ ├── 001-init-notcurses.py │ ├── 002-hello-world.py │ ├── 003-color-example.py │ ├── 004-dimensions.py │ ├── 005-nc-direct-print-used-memory-bars.py │ ├── 006-input-tester.py │ ├── 007-plane_split.py │ ├── 008-put-lines.py │ └── 009-box.py ├── notcurses │ ├── __init__.py │ ├── channels.c │ ├── context.c │ ├── functions.c │ ├── main.c │ ├── misc.c │ ├── notcurses-python.h │ ├── notcurses.py │ ├── plane.c │ └── py.typed └── setup.py ├── src ├── compat │ ├── compat.c │ └── compat.h ├── demo │ ├── animate.c │ ├── box.c │ ├── chunli.c │ ├── demo.c │ ├── demo.h │ ├── dragon.c │ ├── eagle.c │ ├── fission.c │ ├── grid.c │ ├── highcon.c │ ├── hud.c │ ├── input.c │ ├── intro.c │ ├── jungle.c │ ├── keller.c │ ├── luigi.c │ ├── mojibake.c │ ├── normal.c │ ├── outro.c │ ├── qrcode.c │ ├── reel.c │ ├── sliders.c │ ├── trans.c │ ├── uniblock.c │ ├── view.c │ ├── whiteout.c │ ├── xray.c │ ├── yield.c │ └── zoo.c ├── fetch │ ├── main.c │ ├── ncart.c │ └── ncart.h ├── info │ └── main.c ├── input │ └── input.cpp ├── lib │ ├── automaton.c │ ├── automaton.h │ ├── banner.c │ ├── banner.h │ ├── base64.h │ ├── blit.c │ ├── blit.h │ ├── blitset.h │ ├── debug.c │ ├── direct.c │ ├── egcpool.c │ ├── egcpool.h │ ├── fade.c │ ├── fbuf.h │ ├── fd.c │ ├── fill.c │ ├── gpm.c │ ├── gpm.h │ ├── in.c │ ├── in.h │ ├── internal.h │ ├── kitty.c │ ├── layout.c │ ├── linux.c │ ├── linux.h │ ├── logging.h │ ├── menu.c │ ├── metric.c │ ├── mice.c │ ├── notcurses.c │ ├── plot.c │ ├── progbar.c │ ├── reader.c │ ├── reel.c │ ├── render.c │ ├── render.h │ ├── selector.c │ ├── sixel.c │ ├── sixel.h │ ├── sprite.c │ ├── sprite.h │ ├── stats.c │ ├── tabbed.c │ ├── termdesc.c │ ├── termdesc.h │ ├── tree.c │ ├── unixsig.c │ ├── unixsig.h │ ├── util.c │ ├── visual-details.h │ ├── visual.c │ ├── windows.c │ └── windows.h ├── libcpp │ ├── FDPlane.cc │ ├── Menu.cc │ ├── MultiSelector.cc │ ├── NotCurses.cc │ ├── Plane.cc │ ├── Plot.cc │ ├── Reel.cc │ ├── Root.cc │ ├── Selector.cc │ ├── Subproc.cc │ ├── Tablet.cc │ └── Utilities.cc ├── libffi │ └── ffi.c ├── ls │ └── main.cpp ├── man │ ├── main.c │ ├── parse.c │ ├── parse.h │ ├── structure.c │ └── structure.h ├── media │ ├── ffmpeg.c │ ├── none.c │ ├── oiio-indep.c │ ├── oiio.cpp │ ├── oiio.h │ └── shim.c ├── player │ └── play.cpp ├── poc │ ├── bitmapstates.c │ ├── blitters.c │ ├── cjkscroll.c │ ├── cli1.c │ ├── cli2.c │ ├── cli3.c │ ├── direct-input.c │ ├── direct.c │ ├── dirgb.c │ ├── dirlines.c │ ├── fbconscroll.c │ ├── fileroller.c │ ├── gradients.c │ ├── grid.c │ ├── interp.c │ ├── linuxconjammer.c │ ├── linuxconsole.c │ ├── menu.c │ ├── multiselect.c │ ├── ncwidth.c │ ├── pixel.c │ ├── procroller.c │ ├── qrcode.c │ ├── readline.c │ ├── rgb.c │ ├── rotate.c │ ├── rtl.c │ ├── scroll.c │ ├── selector.c │ ├── sgr-direct.c │ ├── sgr-full.c │ ├── statepixel.c │ ├── tabbed.c │ ├── tree.c │ └── zalgo.c ├── pocpp │ ├── ncpp_build.cpp │ ├── ncpp_build_exceptions.cpp │ ├── reader.cpp │ ├── reel.cpp │ ├── resize.cpp │ ├── rgbbg.cpp │ └── widestomp.cpp ├── tests │ ├── Exceptions.cpp │ ├── Ncpp.cpp │ ├── autogrow.cpp │ ├── bitmap.cpp │ ├── blit.cpp │ ├── cell.cpp │ ├── channels.cpp │ ├── direct.cpp │ ├── egcpool.cpp │ ├── erase.cpp │ ├── fade.cpp │ ├── fbuf.cpp │ ├── fds.cpp │ ├── fills.cpp │ ├── geom.cpp │ ├── internal.cpp │ ├── libunistring.cpp │ ├── main.cpp │ ├── main.h │ ├── media.cpp │ ├── menu.cpp │ ├── metric.cpp │ ├── multiselector.cpp │ ├── notcurses.cpp │ ├── output.cpp │ ├── palette.cpp │ ├── piles.cpp │ ├── plane.cpp │ ├── plot.cpp │ ├── progbar.cpp │ ├── reader.cpp │ ├── reel.cpp │ ├── reelgaps.cpp │ ├── resize.cpp │ ├── rotate.cpp │ ├── scrolling.cpp │ ├── selector.cpp │ ├── sixels.cpp │ ├── stacking.cpp │ ├── tabbed.cpp │ ├── tabs.cpp │ ├── textlayout.cpp │ ├── tree.cpp │ ├── version.cpp │ ├── visual.cpp │ ├── wide.cpp │ └── zaxis.cpp └── tetris │ ├── background.h │ ├── clear.h │ ├── gravity.h │ ├── lock.h │ ├── main.cpp │ ├── main.h │ ├── movedown.h │ ├── movelateral.h │ ├── newpiece.h │ ├── rotate.h │ ├── score.h │ ├── stain.h │ ├── stuck.h │ └── ticker.h └── tools ├── Notcurses++Config.cmake.in ├── NotcursesConfig.cmake.in ├── NotcursesCoreConfig.cmake.in ├── builddef.h.in ├── debrelease.sh ├── emojiprep.sh ├── function-table.sh ├── generate_ffi.py ├── interactive-tester.sh ├── neofetch-ripper ├── notcurses++.pc.in ├── notcurses-core.pc.in ├── notcurses-ffi.pc.in ├── notcurses-installer.ifp ├── notcurses.guix ├── notcurses.pc.in ├── nuspec ├── release.sh ├── setup.cfg.in ├── setup.py.in └── version.h.in /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: dankamongmen 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: feature request 3 | about: request new dank warez 4 | title: '' 5 | labels: documentation, enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/problem-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: problem report 3 | about: report issues in code, documentation, packaging 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | Please include the following data: 11 | * `export | egrep 'LANG|LC_CTYPE|TERM'` 12 | * notcurses version (available from `notcurses-demo i`) 13 | * terminal name + version 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: question 3 | about: don't understand how/why something works? 4 | title: '' 5 | labels: userquestion 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/workflows/macos_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: macOS 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | tests: 12 | env: 13 | COLORTERM: truecolor 14 | NPROC: 2 15 | TERM: xterm 16 | name: 🍎 build, test, & install 17 | runs-on: macos-latest 18 | 19 | steps: 20 | 21 | - name: Install tools and libraries via Homebrew 22 | run: | 23 | brew install \ 24 | coreutils \ 25 | doctest \ 26 | ffmpeg \ 27 | libunistring \ 28 | ncurses \ 29 | pkg-config 30 | 31 | - uses: actions/checkout@v2 32 | 33 | - name: cmake 34 | run: | 35 | mkdir build && cd build 36 | env PKG_CONFIG_PATH="/opt/homebrew/opt/ncurses/lib/pkgconfig" \ 37 | cmake .. \ 38 | -DCMAKE_BUILD_TYPE=Release \ 39 | -DUSE_PANDOC=off 40 | 41 | - name: make 42 | run: | 43 | cd build 44 | make -j${NPROC} 45 | 46 | - name: ctest 47 | run: | 48 | cd build 49 | ctest -V --output-on-failure --stop-on-failure 50 | 51 | - name: make install 52 | run: | 53 | cd build 54 | sudo make install 55 | 56 | #- name: python wrappers (old) 57 | #run: | 58 | #python3 -m pip install --upgrade pip 59 | #pip3 install cffi pypandoc 60 | #cd cffi 61 | #python3 setup.py sdist build 62 | #sudo python3 setup.py install 63 | #notcurses-pydemo > /dev/null 64 | #ncdirect-pydemo > /dev/null 65 | 66 | #- name: python wrappers (new) 67 | #run: | 68 | #cd python 69 | #python3 setup.py build 70 | #sudo python3 setup.py install 71 | #python3 examples/000-print-version.py 72 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Ubuntu 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | tests: 12 | env: 13 | COLORTERM: truecolor 14 | NPROC: 2 15 | TERM: xterm 16 | name: 🐧 build, test, & install 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | 21 | - name: Install tools and libraries via APT 22 | run: | 23 | sudo apt update 24 | sudo apt install -y \ 25 | build-essential \ 26 | cmake \ 27 | doctest-dev \ 28 | ffmpeg \ 29 | libavdevice-dev \ 30 | libdeflate-dev \ 31 | libncurses-dev \ 32 | libqrcodegen-dev \ 33 | libswscale-dev \ 34 | libunistring-dev \ 35 | pandoc \ 36 | pkg-config \ 37 | python3-cffi \ 38 | python3-dev \ 39 | python3-setuptools 40 | 41 | - uses: actions/checkout@v2 42 | 43 | - name: cmake 44 | run: | 45 | mkdir build && cd build 46 | cmake .. \ 47 | -DCMAKE_BUILD_TYPE=Release \ 48 | -DUSE_QRCODEGEN=on 49 | 50 | - name: make 51 | run: | 52 | cd build 53 | make -j${NPROC} 54 | 55 | - name: ctest 56 | run: | 57 | cd build 58 | ctest --output-on-failure 59 | 60 | - name: make install 61 | run: | 62 | cd build 63 | sudo make install 64 | sudo ldconfig 65 | 66 | - name: python wrappers (old) 67 | run: | 68 | python3 -m pip install --upgrade pip 69 | pip install pypandoc 70 | cd cffi 71 | python3 setup.py sdist build 72 | sudo python3 setup.py install 73 | notcurses-pydemo > /dev/null 74 | ncdirect-pydemo > /dev/null 75 | 76 | - name: python wrappers (new) 77 | run: | 78 | cd python 79 | python3 setup.py build 80 | sudo python3 setup.py install 81 | python3 examples/000-print-version.py 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | cffi/build 3 | cffi/dist 4 | cffi/src/notcurses.egg-info 5 | doc/examples/book 6 | obj-x86_64-linux-gnu 7 | cffi/include 8 | python/.eggs/ 9 | python/build/ 10 | python/dist/ 11 | python/notcurses-pydemo.1 12 | python/notcurses-direct-pydemo.1 13 | python/src/notcurses.egg-info/ 14 | python/src/_notcurses.so 15 | tools/function-summary/out-* 16 | rust/target 17 | rust/Cargo.lock 18 | *.asc 19 | *.pyc 20 | *.so 21 | *.swp 22 | *.swo 23 | *.xz 24 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureSettings": { "USE_PANDOC": "off", "USE_DOCTEST": "off" } 3 | } 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Notcurses 2 | 3 | Your quality contributions are cheerfully appreciated, however small. Example 4 | code and documentation are especially welcome. 5 | 6 | Changes ought reflect the style of the surrounding matter, whether code or 7 | documentation. The styles used in the C core, the C++ wrappers, and the Rust 8 | wrappers are quite distinct; use the appropriate style for the language. 9 | 10 | New features should have unit tests. It is appreciated if bugfixes have 11 | unit tests, as well. Wrappers in a new language absolutely must have at 12 | least some superficial tests (it is not necessary to deeply test the 13 | underlying functionality in each language). Adding a wrapper implies that 14 | you're prepared to maintain that wrapper; if you can't maintain it, the wrapper 15 | will likely be removed. 16 | 17 | Escape sequences available from terminfo must not be hard-coded. Routines must 18 | check to ensure the relevant escape sequence is valid for the current TERM 19 | definition, and not emit it if invalid. Routines emitting characters beyond 20 | the 128 elements of ASCII should check for UTF8 availability, and fall back to 21 | an ASCII equivalent if not present (or return an error). 22 | 23 | Run `make test` with your changes, and ensure all tests pass. Run 24 | `notcurses-demo` as well, if your changes affect the core library (or the 25 | demo code). 26 | 27 | ## C standard 28 | Notcurses targets the ISO C17 standard. This means you should avoid using 29 | GNU C extensions as they might not work outside GCC/Clang. To verify your 30 | standard compliance on GCC and Clang you can compile with `-std=c17 -pedantic` 31 | command line arguments. 32 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2019-2025 Nick Black 2 | Copyright 2019-2021 Marek Habersack 3 | Copyright 2020-2021 José Luis Cruz 4 | Copyright 2020-2021 igo95862 5 | Copyright 2021 Łukasz Drukała 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | 19 | The contents of src/fetch/ncart.c are extracted from Neofetch, 20 | copyright 2015-2025 Dylan Araps under the MIT License: 21 | 22 | Permission is hereby granted, free of charge, to any person obtaining a copy 23 | of this software and associated documentation files (the "Software"), to deal 24 | in the Software without restriction, including without limitation the rights 25 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | copies of the Software, and to permit persons to whom the Software is 27 | furnished to do so, subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in al 30 | copies or substantial portions of the Software. 31 | 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 38 | SOFTWARE. 39 | -------------------------------------------------------------------------------- /cffi/.gitignore: -------------------------------------------------------------------------------- 1 | .eggs/ 2 | -------------------------------------------------------------------------------- /cffi/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019-2022 Nick Black 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /cffi/MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include include *.h 2 | -------------------------------------------------------------------------------- /cffi/README.md: -------------------------------------------------------------------------------- 1 | # notcurses 2 | 3 | Python bindings for the C [Notcurses](https://github.com/dankamongmen/notcurses) 4 | library. Notcurses is a blingful library for building complex, vibrant textual 5 | user interfaces (TUIs) on modern terminal emulators, of which these Python 6 | bindings offer nowhere near complete coverage. 7 | 8 | by [nick black](https://nick-black.com/dankwiki/index.php/Hack_on) () 9 | 10 | for more information, see [my wiki](https://nick-black.com/dankwiki/index.php/Notcurses). 11 | 12 | [![Build Status](https://drone.dsscaw.com:4443/api/badges/dankamongmen/notcurses/status.svg)](https://drone.dsscaw.com:4443/dankamongmen/notcurses) 13 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 14 | -------------------------------------------------------------------------------- /cffi/ncdirect-pydemo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import locale 4 | from notcurses import notcurses 5 | 6 | def print_b(nc, r, g, total): 7 | b = total - (r + g) 8 | if b > 255: 9 | return 0 10 | ret = nc.setFgRGB8(r, g, b) 11 | print('X', end='') 12 | 13 | def print_gb(nc, r, total): 14 | g = 0 15 | while g <= total - r and g < 256: 16 | print_b(nc, r, g, total) 17 | g += 4 18 | 19 | def print_rgb(nc, total): 20 | r = 0 21 | while r < 256 and r < total: 22 | print_gb(nc, r, total) 23 | r += 1 24 | 25 | def demo(): 26 | nc = notcurses.Ncdirect() 27 | try: 28 | nc.cursorDisable() 29 | except RuntimeError: 30 | print("Couldn't disable cursor") 31 | for t in range(768): 32 | print_rgb(nc, t); 33 | print() 34 | 35 | locale.setlocale(locale.LC_ALL, "") 36 | demo() 37 | -------------------------------------------------------------------------------- /cffi/ncdirect-pydemo.1.md: -------------------------------------------------------------------------------- 1 | % ncdirect-pydemo(1) 2 | % nick black 3 | % v1.6.20 4 | 5 | # NAME 6 | 7 | ncdirect-pydemo - Verify that the ncdirect Python wrappers work 8 | 9 | # SYNOPSIS 10 | 11 | **ncdirect-pydemo** 12 | 13 | # DESCRIPTION 14 | 15 | **ncdirect-pydemo** dumps some stylized output to the attached terminal 16 | using the notcurses Python module's "direct mode" capability (see 17 | **notcurses_direct(3)**. This output is a minimal means of verifying that 18 | the module is correctly installed and can be used in the current environment. 19 | 20 | For a more full-featured demonstration, see **notcurses-demo(1)**. 21 | 22 | # OPTIONS 23 | 24 | # NOTES 25 | 26 | Notcurses supports only Python 3. 27 | 28 | # BUGS 29 | 30 | # SEE ALSO 31 | 32 | **notcurses-demo(1)**, 33 | **notcurses-pydemo(1)**, 34 | **python(1)**, 35 | **notcurses(3)**, 36 | **notcurses_direct(3)** 37 | -------------------------------------------------------------------------------- /cffi/notcurses-pydemo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import locale 4 | from notcurses import notcurses 5 | 6 | def demo(): 7 | nc = notcurses.Notcurses() 8 | stdplane = nc.stdplane() 9 | dims = stdplane.getDimensions() 10 | r = 0x80 11 | g = 0x80 12 | b = 0x80 13 | for y in range(dims[0]): 14 | for x in range(dims[1]): 15 | stdplane.setFgRGB(r, g, b) 16 | stdplane.setBgRGB(b, r, g) 17 | stdplane.putEGCYX(y, x, "X") 18 | b = b + 2 19 | if b == 256: 20 | b = 0 21 | g = g + 2 22 | if g == 256: 23 | g = 0 24 | r = r + 2 25 | nc.render() 26 | 27 | 28 | locale.setlocale(locale.LC_ALL, "") 29 | demo() 30 | -------------------------------------------------------------------------------- /cffi/notcurses-pydemo.1.md: -------------------------------------------------------------------------------- 1 | % notcurses-pydemo(1) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses-pydemo - Verify that the notcurses Python wrappers work 8 | 9 | # SYNOPSIS 10 | 11 | **notcurses-pydemo** 12 | 13 | # DESCRIPTION 14 | 15 | **notcurses-pydemo** dumps some stylized output to the attached terminal using 16 | the notcurses Python module. This output is a minimal means of verifying that 17 | the module is correctly installed and can be used in the current environment. 18 | 19 | For a more full-featured demonstration, see **notcurses-demo(1)**. 20 | 21 | # OPTIONS 22 | 23 | # NOTES 24 | 25 | Notcurses supports only Python 3. 26 | 27 | # BUGS 28 | 29 | # SEE ALSO 30 | 31 | **notcurses-demo(1)**, 32 | **ncdirect-pydemo(1)**, 33 | **python(1)**, 34 | **notcurses(3)** 35 | -------------------------------------------------------------------------------- /cffi/setup.cfg: -------------------------------------------------------------------------------- 1 | [nosetests] 2 | verbosity=1 3 | detailed-errors=1 4 | with-coverage=1 5 | cover-package=nose 6 | debug=nose.loader 7 | pdb=1 8 | pdb-failures=1 9 | -------------------------------------------------------------------------------- /cffi/src/notcurses/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/cffi/src/notcurses/__init__.py -------------------------------------------------------------------------------- /data/PurpleDrank.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/PurpleDrank.jpg -------------------------------------------------------------------------------- /data/Windows10Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/Windows10Logo.png -------------------------------------------------------------------------------- /data/aidsrobots.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/aidsrobots.jpeg -------------------------------------------------------------------------------- /data/atma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/atma.png -------------------------------------------------------------------------------- /data/changes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/changes.jpg -------------------------------------------------------------------------------- /data/changes.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/changes.xcf -------------------------------------------------------------------------------- /data/chunli01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli01.png -------------------------------------------------------------------------------- /data/chunli02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli02.png -------------------------------------------------------------------------------- /data/chunli03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli03.png -------------------------------------------------------------------------------- /data/chunli04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli04.png -------------------------------------------------------------------------------- /data/chunli05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli05.png -------------------------------------------------------------------------------- /data/chunli06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli06.png -------------------------------------------------------------------------------- /data/chunli07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli07.png -------------------------------------------------------------------------------- /data/chunli08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli08.png -------------------------------------------------------------------------------- /data/chunli09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli09.png -------------------------------------------------------------------------------- /data/chunli1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli1.bmp -------------------------------------------------------------------------------- /data/chunli10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli10.png -------------------------------------------------------------------------------- /data/chunli11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli11.png -------------------------------------------------------------------------------- /data/chunli12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli12.png -------------------------------------------------------------------------------- /data/chunli13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli13.png -------------------------------------------------------------------------------- /data/chunli14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli14.png -------------------------------------------------------------------------------- /data/chunli15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli15.png -------------------------------------------------------------------------------- /data/chunli16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli16.png -------------------------------------------------------------------------------- /data/chunli17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli17.png -------------------------------------------------------------------------------- /data/chunli18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli18.png -------------------------------------------------------------------------------- /data/chunli19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli19.png -------------------------------------------------------------------------------- /data/chunli2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli2.bmp -------------------------------------------------------------------------------- /data/chunli20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli20.png -------------------------------------------------------------------------------- /data/chunli21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli21.png -------------------------------------------------------------------------------- /data/chunli22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli22.png -------------------------------------------------------------------------------- /data/chunli23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli23.png -------------------------------------------------------------------------------- /data/chunli24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli24.png -------------------------------------------------------------------------------- /data/chunli25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli25.png -------------------------------------------------------------------------------- /data/chunli26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli26.png -------------------------------------------------------------------------------- /data/chunli27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli27.png -------------------------------------------------------------------------------- /data/chunli28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli28.png -------------------------------------------------------------------------------- /data/chunli29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli29.png -------------------------------------------------------------------------------- /data/chunli3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli3.bmp -------------------------------------------------------------------------------- /data/chunli30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli30.png -------------------------------------------------------------------------------- /data/chunli31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli31.png -------------------------------------------------------------------------------- /data/chunli32.png: -------------------------------------------------------------------------------- 1 | chunli30.png -------------------------------------------------------------------------------- /data/chunli33.png: -------------------------------------------------------------------------------- 1 | chunli29.png -------------------------------------------------------------------------------- /data/chunli34.png: -------------------------------------------------------------------------------- 1 | chunli30.png -------------------------------------------------------------------------------- /data/chunli35.png: -------------------------------------------------------------------------------- 1 | chunli31.png -------------------------------------------------------------------------------- /data/chunli36.png: -------------------------------------------------------------------------------- 1 | chunli30.png -------------------------------------------------------------------------------- /data/chunli37.png: -------------------------------------------------------------------------------- 1 | chunli29.png -------------------------------------------------------------------------------- /data/chunli38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli38.png -------------------------------------------------------------------------------- /data/chunli39.png: -------------------------------------------------------------------------------- 1 | chunli29.png -------------------------------------------------------------------------------- /data/chunli4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli4.bmp -------------------------------------------------------------------------------- /data/chunli40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli40.png -------------------------------------------------------------------------------- /data/chunli41.png: -------------------------------------------------------------------------------- 1 | chunli29.png -------------------------------------------------------------------------------- /data/chunli42.png: -------------------------------------------------------------------------------- 1 | chunli38.png -------------------------------------------------------------------------------- /data/chunli43.png: -------------------------------------------------------------------------------- 1 | chunli29.png -------------------------------------------------------------------------------- /data/chunli44.png: -------------------------------------------------------------------------------- 1 | chunli40.png -------------------------------------------------------------------------------- /data/chunli45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli45.png -------------------------------------------------------------------------------- /data/chunli5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli5.bmp -------------------------------------------------------------------------------- /data/chunli6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli6.bmp -------------------------------------------------------------------------------- /data/chunli7.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli7.bmp -------------------------------------------------------------------------------- /data/chunli8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/chunli8.bmp -------------------------------------------------------------------------------- /data/covid19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/covid19.jpg -------------------------------------------------------------------------------- /data/dsscaw-purp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/dsscaw-purp.png -------------------------------------------------------------------------------- /data/eagles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/eagles.png -------------------------------------------------------------------------------- /data/fm6.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/fm6.mov -------------------------------------------------------------------------------- /data/fonts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/fonts.jpg -------------------------------------------------------------------------------- /data/freebsd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/freebsd.png -------------------------------------------------------------------------------- /data/lamepatents.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/lamepatents.jpg -------------------------------------------------------------------------------- /data/megaman2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/megaman2.bmp -------------------------------------------------------------------------------- /data/natasha-blur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/natasha-blur.png -------------------------------------------------------------------------------- /data/natasha-blur.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/natasha-blur.xcf -------------------------------------------------------------------------------- /data/normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/normal.png -------------------------------------------------------------------------------- /data/normal.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/normal.xcf -------------------------------------------------------------------------------- /data/notcurses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/notcurses.png -------------------------------------------------------------------------------- /data/notcursesIII.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/notcursesIII.mov -------------------------------------------------------------------------------- /data/onedot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/onedot.png -------------------------------------------------------------------------------- /data/samoa.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/samoa.avi -------------------------------------------------------------------------------- /data/spaceship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/spaceship.png -------------------------------------------------------------------------------- /data/tetris-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/tetris-background.jpg -------------------------------------------------------------------------------- /data/tetris-background.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/tetris-background.xcf -------------------------------------------------------------------------------- /data/warmech.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/warmech.bmp -------------------------------------------------------------------------------- /data/worldmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/data/worldmap.png -------------------------------------------------------------------------------- /doc/analytics-header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /doc/examples/Makefile: -------------------------------------------------------------------------------- 1 | .DELETE_ON_ERROR: 2 | .PHONY: all book serve clean 3 | .DEFAULT_GOAL:=all 4 | 5 | SRC:=$(wildcard src/*.c) 6 | BIN:=$(foreach src, $(SRC), $(addprefix book/,$(notdir $(basename $(src))))) 7 | 8 | all: $(BIN) 9 | 10 | serve: book 11 | mdbook serve 12 | 13 | book: $(SRC) 14 | mdbook build 15 | 16 | book/%: src/%.c 17 | @mkdir -p $(@D) 18 | $(CC) -o $@ $< -lnotcurses 19 | 20 | clean: 21 | rm -rf $(BIN) book 22 | -------------------------------------------------------------------------------- /doc/examples/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["nick black"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "A Gentle Introduction to Notcurses" 7 | -------------------------------------------------------------------------------- /doc/examples/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Basics](./basics.md) 4 | - [Direct mode](./directmode.md) 5 | - [Rendered mode](./rendered.md) 6 | - [Writing text](./writetext.md) 7 | - [Colors](./colors.md) 8 | - [Drawing boxes](./boxes.md) 9 | - [Reading input](./input.md) 10 | - [Planes and transparency](./planes.md) 11 | - [Selector widgets](./selectors.md) 12 | - [Menus](./menus.md) 13 | - [Plots and progress bars](./plots.md) 14 | - [Rendering media](./media.md) 15 | - [Subprocesses](./fdwidget.md) 16 | - [The reader widget](./reader.md) 17 | - [Reels](./reels.md) 18 | -------------------------------------------------------------------------------- /doc/examples/src/boxes.md: -------------------------------------------------------------------------------- 1 | # Boxes 2 | -------------------------------------------------------------------------------- /doc/examples/src/colors.md: -------------------------------------------------------------------------------- 1 | # Colors 2 | -------------------------------------------------------------------------------- /doc/examples/src/directmode-helloworld.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void){ 5 | struct ncdirect* n = ncdirect_init(NULL, NULL, 0); 6 | if(n == NULL){ 7 | return EXIT_FAILURE; 8 | } 9 | if(ncdirect_set_fg_rgb(n, 0x00aaaa) || printf("oh yeaaaaaaaaah\n") < 0){ 10 | ncdirect_stop(n); 11 | return EXIT_FAILURE; 12 | } 13 | return ncdirect_stop(n) ? EXIT_FAILURE : EXIT_SUCCESS; 14 | } 15 | -------------------------------------------------------------------------------- /doc/examples/src/directmode-helloworld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/examples/src/directmode-helloworld.png -------------------------------------------------------------------------------- /doc/examples/src/fdwidget.md: -------------------------------------------------------------------------------- 1 | # Subprocesses 2 | -------------------------------------------------------------------------------- /doc/examples/src/input.md: -------------------------------------------------------------------------------- 1 | # Reading input 2 | -------------------------------------------------------------------------------- /doc/examples/src/media.md: -------------------------------------------------------------------------------- 1 | # Rendering media 2 | -------------------------------------------------------------------------------- /doc/examples/src/menus.md: -------------------------------------------------------------------------------- 1 | # Menus 2 | -------------------------------------------------------------------------------- /doc/examples/src/planes.md: -------------------------------------------------------------------------------- 1 | # Planes and transparency 2 | -------------------------------------------------------------------------------- /doc/examples/src/plots.md: -------------------------------------------------------------------------------- 1 | # Plots and progress bars 2 | -------------------------------------------------------------------------------- /doc/examples/src/reader.md: -------------------------------------------------------------------------------- 1 | # The reader widget 2 | -------------------------------------------------------------------------------- /doc/examples/src/reels.md: -------------------------------------------------------------------------------- 1 | # Reels 2 | -------------------------------------------------------------------------------- /doc/examples/src/rendered.md: -------------------------------------------------------------------------------- 1 | # Rendered mode 2 | -------------------------------------------------------------------------------- /doc/examples/src/selectors.md: -------------------------------------------------------------------------------- 1 | # Selector widgets 2 | -------------------------------------------------------------------------------- /doc/examples/src/writetext.md: -------------------------------------------------------------------------------- 1 | # Writing text 2 | -------------------------------------------------------------------------------- /doc/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/icon.ico -------------------------------------------------------------------------------- /doc/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/icon.png -------------------------------------------------------------------------------- /doc/logo-1280x640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/logo-1280x640.png -------------------------------------------------------------------------------- /doc/logo-200x55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/logo-200x55.png -------------------------------------------------------------------------------- /doc/man/man1/ncls.1.md: -------------------------------------------------------------------------------- 1 | % ncls(1) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | ncls - List paths with rendering of multimedia 8 | 9 | # SYNOPSIS 10 | 11 | **ncls** [**-h**|**--help**] [**-V**|**--version**] [**-d**] [**-l**] [**-L**] [**-R**] [**-a**|**--align** ***type***] [**-b**|**--blitter** ***blitter***] [**-s**|**--scale** ***scale***] [ paths ] 12 | 13 | # DESCRIPTION 14 | 15 | **ncls** uses a multimedia-enabled Notcurses to list paths, similarly to the 16 | **ls(1)** command, rendering images and videos to a terminal. 17 | 18 | # OPTIONS 19 | 20 | **-d**: list directories themselves, not their contents. 21 | 22 | **-l**: use a long listing format. 23 | 24 | **-L**: dereference symbolic links 25 | 26 | **-R**: list subdirectories recursively. 27 | 28 | **-V**|**--version**: Print version information, and exit with success. 29 | 30 | **-h**|**--help**: Print help information, and exit with success. 31 | 32 | **-a**|**--align** ***type***: Align images on **left**, **center**, or **right**. 33 | 34 | **-b**|**--blitter** ***blitter***: Blitter, one of **ascii**, **half**, 35 | **quad**, **sex**, **braille**, or **pixel**. The default is **pixel**. 36 | If the chosen blitter is unavailable, **ncls** will degrade (see 37 | **notcurses_visual(3)**). 38 | 39 | **-s**|**--scale** ***scalemode***: Scaling mode, one of **none**, **hires**, 40 | **scale**, **scalehi**, or **stretch**. 41 | 42 | paths: Run on the specified paths. If none are supplied, run on the current 43 | directory. 44 | 45 | If no scaling is specified, **hires** will be used with the **pixel** blitter, 46 | and **scalehi** will be used otherwise. 47 | 48 | # NOTES 49 | 50 | Optimal display requires a terminal advertising the **rgb** terminfo(5) 51 | capability, or that the environment variable **COLORTERM** is defined to 52 | **24bit** (and that the terminal honors this variable), along with a 53 | fixed-width font with good coverage of the Unicode Block Drawing Characters. 54 | 55 | # SEE ALSO 56 | 57 | **notcurses(3)**, 58 | **notcurses_visual(3)**, 59 | **terminfo(5)**, 60 | **unicode(7)** 61 | -------------------------------------------------------------------------------- /doc/man/man1/ncneofetch.1.md: -------------------------------------------------------------------------------- 1 | % ncneofetch(1) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | ncneofetch - Generate low-effort posts for r/unixporn 8 | 9 | # SYNOPSIS 10 | 11 | **ncneofetch** [**-v**] 12 | 13 | # DESCRIPTION 14 | 15 | **ncneofetch** renders an image (typically a distribution logo) 16 | and displays some system information. It is a blatant ripoff of 17 | **neofetch(1)** using **notcurses(3)**. 18 | 19 | # OPTIONS 20 | 21 | **-v**: Increase verbosity. 22 | 23 | # NOTES 24 | 25 | Optimal display requires a terminal advertising the **rgb** terminfo(5) 26 | capability, or that the environment variable **COLORTERM** is defined to 27 | **24bit** (and that the terminal honors RGB escapes), along with a good 28 | monospaced font supporting the Unicode Block Drawing Characters. 29 | 30 | # SEE ALSO 31 | 32 | **neofetch(1)**, 33 | **notcurses(3)** 34 | -------------------------------------------------------------------------------- /doc/man/man1/nctetris.1.md: -------------------------------------------------------------------------------- 1 | % nctetris(1) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | nctetris - Тетрис in the terminal 8 | 9 | # SYNOPSIS 10 | 11 | **nctetris** [**-h|--help**] [**-l loglevel**] 12 | 13 | # DESCRIPTION 14 | 15 | **nctetris** implements a Tetris clone using Notcurses. 16 | 17 | The goal is to complete horizontal lines, without allowing tetriminos to 18 | reach the top of the screen. The falling tetrimino can be rotated counter- 19 | clockwise with the 'z' key, and clockwise with the 'x' key. The tetrimino 20 | can be moved left and right with 'h' and 'l', respectively. It can be moved 21 | down with 'j'. The arrow keys can also be used. Quit with 'q'. 22 | 23 | # OPTIONS 24 | 25 | **-h**: Show help and exit. 26 | 27 | **-l loglevel**: Log everything (high log level) or nothing (log level 0) to stderr. 28 | 29 | # NOTES 30 | 31 | Optimal display requires a terminal advertising the **rgb** terminfo(5) 32 | capability, or that the environment variable **COLORTERM** is defined to 33 | **24bit** (and that the terminal honors RGB escapes), along with a good 34 | fixed-width font with good coverage of the Unicode Block Drawing Characters. 35 | 36 | # SEE ALSO 37 | 38 | **notcurses(3)** 39 | -------------------------------------------------------------------------------- /doc/man/man1/notcurses-input.1.md: -------------------------------------------------------------------------------- 1 | % notcurses-input(1) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses-input - Read and display input events 8 | 9 | # SYNOPSIS 10 | 11 | **notcurses-input** [**-v**] [**-m**] 12 | 13 | # DESCRIPTION 14 | 15 | **notcurses-input** reads from stdin and decodes the input to stdout, including 16 | synthesized events and mouse events. To exit, generate EOF (usually Ctrl+'d'). 17 | 18 | Each event will be printed on a single line. Leading that line is a series 19 | of modifier indicators: 20 | 21 | * 'A'/'a': Alt was or was not pressed. 22 | * 'C'/'c': Ctrl was or was not pressed. 23 | * 'S'/'s': Shift was or was not pressed. 24 | * 'U'/'u': Super was or was not pressed 25 | * 'M'/'m': Meta was or was not pressed. 26 | * 'H'/'h': Hyper was or was not pressed. 27 | * 'X'/'x': CapsLock was or was not pressed. 28 | * '#'/'.': NumLock was or was not pressed. 29 | * 'L'/'R'/'P'/'u': Key was a release, repeat, press, or of unknown type. 30 | 31 | By default, mice events are enabled. 32 | 33 | # OPTIONS 34 | 35 | **-v**: Increase verbosity. 36 | **-m**: Inhibit mice events. 37 | 38 | # NOTES 39 | 40 | Mouse events are only generated for button presses and releases, and for 41 | movement while a button is held down. 42 | 43 | # SEE ALSO 44 | 45 | **tack(1)**, 46 | **notcurses(3)**, 47 | **notcurses_input(3)** 48 | -------------------------------------------------------------------------------- /doc/man/man1/notcurses-tester.1.md: -------------------------------------------------------------------------------- 1 | % notcurses-tester(1) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses-tester - Notcurses unit testing 8 | 9 | # SYNOPSIS 10 | 11 | **notcurses-tester** [**-p datadir**] [**-lN**] 12 | 13 | # DESCRIPTION 14 | 15 | **notcurses-tester** drives the several hundred unit tests included with 16 | Notcurses. It requires several data files installed alongside Notcurses; 17 | if these are in an irregular location, supply **-p**. 18 | 19 | # OPTIONS 20 | 21 | **-p** ***path***: Look in the specified ***path*** for data files. 22 | 23 | **-lN**: Enable diagnostics/logging at level ***N***. ***N*** must be 24 | between -1 and 7. 25 | 26 | # NOTES 27 | 28 | Valid **TERM** and **LANG** environment variables are necessary for 29 | **notcurses-tester**'s correct operation. 30 | 31 | # SEE ALSO 32 | 33 | **notcurses(3)** 34 | -------------------------------------------------------------------------------- /doc/man/man1/tfman.1.md: -------------------------------------------------------------------------------- 1 | % tfman(1) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | tfman - Swank manual page browser 8 | 9 | # SYNOPSIS 10 | 11 | **tfman** [**-h**] [**-V**] [**-q**] files 12 | 13 | # DESCRIPTION 14 | 15 | **tfman** displays manual pages ala **man(1)** using the Notcurses 16 | (**notcurses(3)**) terminal UI library. 17 | 18 | # OPTIONS 19 | 20 | **-V**: Print the program name and version, and exit with success. 21 | 22 | **-h**: Print help information, and exit with success. 23 | 24 | **-q**: Don't wait for any input, and don't use the alternate screen. 25 | 26 | files: Files to render. 27 | 28 | If successfully loaded and parsed, the top of the page will be visible. 29 | In the lower right corner is a listing of page sections. By default, the 30 | page browser is in use; press Tab to move between the page browser and 31 | the structure browser. Press 's' to toggle the structure browser's 32 | visibility. 33 | 34 | **tfman** can identify gzipped manual pages, and inflate them on the fly. 35 | 36 | # NOTES 37 | 38 | The following keypresses are recognized: 39 | 40 | * **Ctrl-L**: Redraw the screen. 41 | * **q**: Quit. 42 | * **k**/**up**: Move up by one line. 43 | * **b**/**pgup**: Move up by one page. 44 | * **h**/**left**: Move up by one section. 45 | * **j**/**down**: Move down by one line. 46 | * **f**/**pgdown**: Move down by one page. 47 | * **l**/**right**: Move down by one section. 48 | * **g**/**home**: Go to first line in file. 49 | * **s**: Toggle the structure browser's visibility. 50 | 51 | The mouse wheel can also be used to move up and down within the active browser. 52 | 53 | # BUGS 54 | 55 | **tfman** does not currently (and is unlikely to ever) support the full 56 | **groff** macro language. 57 | 58 | # SEE ALSO 59 | 60 | **man(1)**, 61 | **notcurses(3)**, 62 | **groff_man(7)**, 63 | **man-pages(7)**, 64 | **unicode(7)** 65 | -------------------------------------------------------------------------------- /doc/man/man3/notcurses_core.3.md: -------------------------------------------------------------------------------- 1 | % notcurses_core(3) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses_core - minimal Notcurses linkage 8 | 9 | # SYNOPSIS 10 | 11 | **#include ** 12 | 13 | **-lnotcurses-core** 14 | 15 | **struct notcurses* notcurses_core_init(const notcurses_options* ***opts***, FILE* ***fp***);** 16 | 17 | **struct ncdirect* ncdirect_core_init(const char* ***termtype***, FILE* ***fp***, uint64_t ***flags***);** 18 | 19 | # DESCRIPTION 20 | 21 | If your binary has no use for the multimedia capabilities of Notcurses, 22 | consider linking directly to **libnotcurses-core** rather than 23 | **libnotcurses**. This ought greatly reduce the dependency burden of 24 | Notcurses. 25 | 26 | If using **libnotcurses-core**, **notcurses_core_init** must be 27 | used in the place of **notcurses_init**, and **ncdirect_core_init** must 28 | be used in the place of **ncdirect_init**. Failure to do will usually 29 | result in an error during linking. At worst, you'll end up with the 30 | unnecessary dependencies in your binary after all. 31 | 32 | # BUGS 33 | 34 | This all ought be handled by the toolchain. It's stupid for users to have 35 | to think about this. 36 | 37 | # NOTES 38 | 39 | If Notcurses was built with **USE_MULTIMEDIA=none**, **libnotcurses** will 40 | have no multimedia dependencies, and thus this won't save anything. It's 41 | still best to explicitly use **libnotcurses-core** when appropriate, to 42 | avoid picking up the dependency chain on systems where it *is* being used. 43 | 44 | # RETURN VALUES 45 | 46 | The same as **notcurses_init** and **ncdirect_init**. 47 | 48 | # SEE ALSO 49 | 50 | **notcurses(3)**, 51 | **notcurses_direct(3)**, 52 | **notcurses_init(3)**, 53 | **utf8(7)** 54 | -------------------------------------------------------------------------------- /doc/man/man3/notcurses_palette.3.md: -------------------------------------------------------------------------------- 1 | % notcurses_palette(3) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses_palette - operations on notcurses palettes 8 | 9 | # SYNOPSIS 10 | 11 | **#include ** 12 | 13 | ```c 14 | typedef struct ncpalette { 15 | // We store the RGB values as a regular ol' channel 16 | uint32_t chans[NCPALETTESIZE]; 17 | } ncpalette; 18 | ``` 19 | 20 | **bool notcurses_cantruecolor(const struct notcurses* ***nc***);** 21 | 22 | **ncpalette* ncpalette_new(struct notcurses* ***nc***);** 23 | 24 | **int ncpalette_use(struct notcurses* ***nc***, const ncpalette* ***p***);** 25 | 26 | **int ncpalette_set_rgb8(ncpalette* ***p***, int ***idx***, int ***r***, int ***g***, int ***b***);** 27 | 28 | **int ncpalette_set(ncpalette* ***p***, int ***idx***, unsigned ***rgb***);** 29 | 30 | **int ncpalette_get(const ncpalette* ***p***, int ***idx***, uint32_t* ***palent***);** 31 | 32 | **int ncpalette_get_rgb8(const ncpalette* ***p***, int ***idx***, int* restrict ***r***, int* restrict ***g***, int* restrict ***b***);** 33 | 34 | **void ncpalette_free(ncpalette* ***p***);** 35 | 36 | **bool notcurses_canchangecolors(const struct notcurses* ***nc***);** 37 | 38 | # DESCRIPTION 39 | 40 | Some terminals only support 256 colors, but allow the full palette to be 41 | specified with arbitrary RGB colors. In all cases, it's more performant to use 42 | indexed colors, since it's much less data to write to the terminal. If you can 43 | limit yourself to 256 colors, that's probably for the best. 44 | 45 | In addition, palette-based color allows for very fast color cycling effects, 46 | since a single command can affect many cells on the screen. 47 | 48 | # RETURN VALUES 49 | 50 | Functions returning **int** return -1 on failure, or 0 on success. Failure is 51 | always due to invalid inputs. Functions returning **bool** are predicates, and 52 | return the requested value. Functions returning **unsigned** forms return the 53 | input, modified as requested. 54 | 55 | # SEE ALSO 56 | 57 | **notcurses(3)**, 58 | **notcurses_cell(3)**, 59 | **notcurses_channels(3)**, 60 | **notcurses_output(3)**, 61 | **notcurses_plane(3)** 62 | -------------------------------------------------------------------------------- /doc/man/man3/notcurses_pile.3.md: -------------------------------------------------------------------------------- 1 | % notcurses_pile(3) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses_pile - operations on Notcurses piles 8 | 9 | # SYNOPSIS 10 | 11 | **struct ncplane* notcurses_top(struct notcurses* ***n***);** 12 | 13 | **struct ncplane* notcurses_bottom(struct notcurses* ***n***);** 14 | 15 | **struct ncplane* ncpile_top(struct ncplane* ***n***);** 16 | 17 | **struct ncplane* ncpile_bottom(struct ncplane* ***n***);** 18 | 19 | # DESCRIPTION 20 | 21 | Notcurses does not export the **ncpile** type, nor any functionality that 22 | uses it directly. Piles are nonetheless an important concept in Notcurses. 23 | Functions which operate on piles (e.g. **ncpile_render(3)** are invoked 24 | with any **ncplane** within that pile. 25 | 26 | Piles are collections of **ncplane**s, independent from one another for 27 | purposes of rendering and also thread-safety. While only one pile can be 28 | rasterized (written to the display) at a time, arbitrary concurrent actions 29 | can be safely performed on distinct piles. Piles do not compose: rasterizing 30 | a pile destroys any overlapping material. 31 | 32 | A pile is created in one of three ways: 33 | 34 | * **ncpile_create(3)** is called, 35 | * **ncvisual_blit(3)** is called with a **NULL** target plane ***n***, or 36 | * **ncplane_reparent(3)** is called with ***n*** equal to ***newparent***, 37 | and ***n*** is not already a root plane. 38 | 39 | A pile is destroyed whenever its last **ncplane** is destroyed, or 40 | reparented into some other pile. 41 | 42 | The planes of a pile are totally ordered along the z-axis. **ncpile_top** and 43 | **ncpile_bottom** return the topmost and bottommost planes, respectively, of 44 | the pile containing their argument. **notcurses_top** and **notcurses_bottom** 45 | do the same for the standard pile. 46 | 47 | # NOTES 48 | 49 | # BUGS 50 | 51 | # SEE ALSO 52 | 53 | **notcurses(3)**, 54 | **notcurses_plane(3)**, 55 | **notcurses_render(3)**, 56 | **notcurses_visual(3)** 57 | -------------------------------------------------------------------------------- /doc/man/man3/notcurses_stop.3.md: -------------------------------------------------------------------------------- 1 | % notcurses_stop(3) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses_stop - free up resources and restore initial terminal state 8 | 9 | # SYNOPSIS 10 | 11 | **#include ** 12 | 13 | **int notcurses_stop(struct notcurses* ***nc***);** 14 | 15 | # DESCRIPTION 16 | 17 | **notcurses_stop** frees up any resources associated with the 18 | **struct notcurses** provided as **nc**, and attempts to restore the terminal to its 19 | state prior to calling **notcurses_init(3)**. It also unregisters any signal 20 | handlers put into place by **notcurses_init(3)**. **nc** must not be used 21 | following the call, and all references to ncplanes, cells, etc. are 22 | invalidated. 23 | 24 | Once the terminal has been reset, a summary of runtime and performance is 25 | printed, unless **NCOPTION_SUPPRESS_BANNERS** was provided to 26 | **notcurses_init(3)**. 27 | 28 | The first step taken by **notcurses_stop** is a call to the internal function 29 | **notcurses_stop_minimal**. This is the same function called by the fatal 30 | signal handlers installed in the absence of **NCOPTION_NO_QUIT_SIGHANDLERS**. 31 | This function: 32 | 33 | * Disables the Notcurses signal handlers 34 | * Emits the **op** terminfo capability, if supported 35 | * Emits the **sgr0** terminfo capability, if supported 36 | * Emits the **oc** terminfo capability, if supported 37 | * Emits the **rmcup** terminfo capability, if supported (and if 38 | **NCOPTION_NO_ALTERNATE_SCREEN** was not provided). 39 | * Emits the **cnorm** terminfo capability, if supported 40 | 41 | Respectively, these restore the default colorpair to its original value 42 | (**op**), turn off all text attributes (**sgr0**), restore the default 43 | palette (**oc**), exit the alternate screen (**rmcup**), and restore the 44 | cursor to its default appearance (**cnorm**). 45 | 46 | It is legal to pass **NULL** to **notcurses_stop**. This is a no-op. 47 | 48 | # NOTES 49 | 50 | Behavior is undefined if other threads are working with **nc** when or after 51 | this function is called. It is unlikely to be good. 52 | 53 | # RETURN VALUES 54 | 55 | On success, 0 is returned. Otherwise, a negative value is returned. 56 | 57 | # SEE ALSO 58 | 59 | **notcurses(3)**, 60 | **notcurses_init(3)**, 61 | **terminfo(5)** 62 | -------------------------------------------------------------------------------- /doc/man/man3/notcurses_util.3.md: -------------------------------------------------------------------------------- 1 | % notcurses_util(3) 2 | % nick black 3 | % v3.0.16 4 | 5 | # NAME 6 | 7 | notcurses_util - portable utility functions 8 | 9 | # SYNOPSIS 10 | 11 | **#include ** 12 | 13 | **char* notcurses_accountname(void);** 14 | 15 | **char* notcurses_hostname(void);** 16 | 17 | **char* notcurses_osversion(void);** 18 | 19 | # DESCRIPTION 20 | 21 | Notcurses provides some utility functions, usually to abstract away 22 | platform-dependent differences. 23 | 24 | **notcurses_accountname** returns a heap-allocated copy of the account 25 | name under which the program is running. **notcurses_hostname** returns 26 | a heap-allocated copy of the local host name. **notcurses_osversion** 27 | returns a heap-allocated human-readable representation of the operating 28 | system and its version. 29 | 30 | # NOTES 31 | 32 | # RETURN VALUES 33 | 34 | All functions return ***NULL*** on error. 35 | 36 | # SEE ALSO 37 | 38 | **hostname(1)**, 39 | **notcurses(3)** 40 | -------------------------------------------------------------------------------- /doc/proposed-terminfo.md: -------------------------------------------------------------------------------- 1 | # Some desirable terminfo capabilities 2 | 3 | ## Semigraphics 4 | 5 | ### blocks 6 | 7 | The `blocks` capability indicates that block characters are drawn by the 8 | terminal itself, rather than through rendering the current font. This should 9 | cover at least: 10 | 11 | * The entirety of the [Block Elements](https://www.unicode.org/charts/PDF/U2580.pdf) 12 | block (U+2580–U+259F). 13 | * The entirety of the [Geometric Shapes](https://www.unicode.org/charts/PDF/U25A0.pdf) 14 | block (U+25A0–U+25FF). 15 | * The [Symbols for Legacy Computing](https://www.unicode.org/charts/PDF/U1FB00.pdf) 16 | block from U+1FB00 through U+1FBAF, except U+1FB70–U+1FB7F. 17 | 18 | ### boxes 19 | 20 | The `boxes` capability indicates that box characters are drawn by the terminal 21 | itself, rather than through rendering the current font. This should cover at 22 | least: 23 | 24 | * The entirety of the [Box Drawing](https://www.unicode.org/charts/PDF/U2500.pdf) 25 | block (U+2500–U+257F). 26 | * Symbols U+1FB70–U+1FB7F from the [Symbols for Legacy Computing](https://www.unicode.org/charts/PDF/U1FB00.pdf) block. 27 | -------------------------------------------------------------------------------- /doc/sexblitter-perfection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/sexblitter-perfection.png -------------------------------------------------------------------------------- /doc/sexblitter-perfection.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/sexblitter-perfection.xcf -------------------------------------------------------------------------------- /doc/testing-checklist.md: -------------------------------------------------------------------------------- 1 | # Release testing 2 | 3 | ## Unit tests 4 | 5 | Run unit tests (`make && make test`): 6 | * In each multimedia configuration (`ffmpeg`, `oiio`, `none`) 7 | * With `LANG` set to `fr_FR.UTF-8` (to test comma as decimal separator) 8 | * With `LANG` set to `C` (to test ASCII mode, necessary for debuilder) 9 | * All must pass 10 | 11 | ## Manual tests 12 | 13 | Run, using `valgrind --tool=memcheck --leak-check=full`: 14 | * `notcurses-demo` in each of the three multimedia configurations 15 | * `notcurses-demo` with `USE_QRCODEGEN=off` 16 | * `notcurses-demo` in ASCII mode (`export LANG=C`) 17 | * `notcurses-input` 18 | * `ncplayer` with each scaling mode and an image + video, in three 19 | terminal geometries: square, tall, wide 20 | * `notcurses-demo` with margins 21 | * `notcurses-demo` with FPS plot and HUD up 22 | * Play a game of `nctetris` 23 | * Run each PoC binary, including `ncpp_build` and `ncpp_build_exceptions` 24 | 25 | Bitmap tests; all must be done in both Sixel and Kitty environments: 26 | * `ncplayer -bpixel`, make sure frame count/time is always visible 27 | * `ncplayer -bpixel`, make sure we can switch to cells and back 28 | * `ncplayer`, make sure we can switch into pixel and back 29 | * `notcurses-demo k`, make sure bitmaps are deleted 30 | * `notcurses-demo y`, make sure yield is always visible 31 | All of these need to work without flicker. 32 | -------------------------------------------------------------------------------- /doc/worldmap-sexblitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/worldmap-sexblitter.png -------------------------------------------------------------------------------- /doc/worldmap-sexblitter.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/doc/worldmap-sexblitter.xcf -------------------------------------------------------------------------------- /include/ncpp/CellStyle.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_NCSTYLE_HH 2 | #define __NCPP_NCSTYLE_HH 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "_flag_enum_operator_helpers.hh" 9 | 10 | namespace ncpp 11 | { 12 | enum class CellStyle : uint32_t 13 | { 14 | None = 0, 15 | Underline = NCSTYLE_UNDERLINE, 16 | Bold = NCSTYLE_BOLD, 17 | Italic = NCSTYLE_ITALIC, 18 | Struck = NCSTYLE_STRUCK, 19 | Undercurl = NCSTYLE_UNDERCURL, 20 | }; 21 | 22 | DECLARE_ENUM_FLAG_OPERATORS (CellStyle) 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /include/ncpp/FDPlane.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_FDPLANE_HH 2 | #define __NCPP_FDPLANE_HH 3 | 4 | #include 5 | 6 | #include "Utilities.hh" 7 | #include "Plane.hh" 8 | #include "Widget.hh" 9 | 10 | namespace ncpp 11 | { 12 | class NCPP_API_EXPORT FDPlane : public Widget 13 | { 14 | public: 15 | static ncfdplane_options default_options; 16 | 17 | public: 18 | explicit FDPlane (Plane *plane, int fd, ncfdplane_callback cbfxn = nullptr, ncfdplane_done_cb donecbfxn = nullptr) 19 | : FDPlane (plane, fd, nullptr, cbfxn, donecbfxn) 20 | {} 21 | 22 | explicit FDPlane (Plane *plane, int fd, ncfdplane_options *opts = nullptr, ncfdplane_callback cbfxn = nullptr, ncfdplane_done_cb donecbfxn = nullptr) 23 | : Widget (Utilities::get_notcurses_cpp (plane)) 24 | { 25 | ensure_valid_plane (plane); 26 | create_fdplane (*plane, fd, opts, cbfxn, donecbfxn); 27 | take_plane_ownership (plane); 28 | } 29 | 30 | explicit FDPlane (Plane &plane, int fd, ncfdplane_callback cbfxn = nullptr, ncfdplane_done_cb donecbfxn = nullptr) 31 | : FDPlane (plane, fd, nullptr, cbfxn, donecbfxn) 32 | {} 33 | 34 | explicit FDPlane (Plane &plane, int fd, ncfdplane_options *opts = nullptr, ncfdplane_callback cbfxn = nullptr, ncfdplane_done_cb donecbfxn = nullptr) 35 | : Widget (Utilities::get_notcurses_cpp (plane)) 36 | { 37 | ensure_valid_plane (plane); 38 | create_fdplane (plane, fd, opts, cbfxn, donecbfxn); 39 | take_plane_ownership (plane); 40 | } 41 | 42 | ~FDPlane () 43 | { 44 | if (is_notcurses_stopped ()) 45 | return; 46 | 47 | ncfdplane_destroy (fdplane); 48 | } 49 | 50 | Plane* get_plane () const noexcept 51 | { 52 | return Plane::map_plane (ncfdplane_plane (fdplane)); 53 | } 54 | 55 | private: 56 | void create_fdplane (Plane& n, int fd, ncfdplane_options *opts, ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn) 57 | { 58 | fdplane = ncfdplane_create ( 59 | n, 60 | opts == nullptr ? &default_options : opts, 61 | fd, 62 | cbfxn, 63 | donecbfxn 64 | ); 65 | 66 | if (fdplane == nullptr) 67 | throw init_error ("NotCurses failed to create an ncfdplane instance"); 68 | } 69 | 70 | private: 71 | ncfdplane *fdplane; 72 | }; 73 | } 74 | #endif // __NCPP_FDPLANE_HH 75 | -------------------------------------------------------------------------------- /include/ncpp/Menu.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_MENU_HH 2 | #define __NCPP_MENU_HH 3 | 4 | #include 5 | 6 | #include "Root.hh" 7 | 8 | namespace ncpp 9 | { 10 | class NotCurses; 11 | class Plane; 12 | 13 | class NCPP_API_EXPORT Menu : public Root 14 | { 15 | public: 16 | static ncmenu_options default_options; 17 | 18 | public: 19 | explicit Menu (const ncmenu_options *opts = nullptr, NotCurses *ncinst = nullptr) 20 | : Root (ncinst) 21 | { 22 | menu = ncmenu_create (notcurses_stdplane (get_notcurses ()), opts == nullptr ? &default_options : opts); 23 | if (menu == nullptr) 24 | throw init_error ("Notcurses failed to create a new menu"); 25 | } 26 | 27 | ~Menu () 28 | { 29 | if (!is_notcurses_stopped ()) 30 | ncmenu_destroy (menu); 31 | } 32 | 33 | bool unroll (int sectionidx) const NOEXCEPT_MAYBE 34 | { 35 | return error_guard (ncmenu_unroll (menu, sectionidx), -1); 36 | } 37 | 38 | bool rollup () const NOEXCEPT_MAYBE 39 | { 40 | return error_guard (ncmenu_rollup (menu), -1); 41 | } 42 | 43 | bool nextsection () const NOEXCEPT_MAYBE 44 | { 45 | return error_guard (ncmenu_nextsection (menu), -1); 46 | } 47 | 48 | bool prevsection () const NOEXCEPT_MAYBE 49 | { 50 | return error_guard (ncmenu_prevsection (menu), -1); 51 | } 52 | 53 | bool nextitem () const NOEXCEPT_MAYBE 54 | { 55 | return error_guard (ncmenu_nextitem (menu), -1); 56 | } 57 | 58 | bool previtem () const NOEXCEPT_MAYBE 59 | { 60 | return error_guard (ncmenu_previtem (menu), -1); 61 | } 62 | 63 | bool item_set_status (const char* section, const char* item, bool status) const NOEXCEPT_MAYBE 64 | { 65 | return error_guard (ncmenu_item_set_status (menu, section, item, status), -1); 66 | } 67 | 68 | const char* get_selected (ncinput *ni = nullptr) const noexcept 69 | { 70 | return ncmenu_selected (menu, ni); 71 | } 72 | 73 | const char* get_mouse_selected (const struct ncinput* click, struct ncinput* ni) const noexcept 74 | { 75 | return ncmenu_mouse_selected (menu, click, ni); 76 | } 77 | 78 | bool offer_input (const struct ncinput* ni) const noexcept 79 | { 80 | return ncmenu_offer_input (menu, ni); 81 | } 82 | 83 | Plane* get_plane () const noexcept; 84 | 85 | private: 86 | ncmenu *menu; 87 | }; 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /include/ncpp/MultiSelector.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_MULTI_SELECTOR_HH 2 | #define __NCPP_MULTI_SELECTOR_HH 3 | 4 | #include 5 | 6 | #include "NCAlign.hh" 7 | #include "Plane.hh" 8 | #include "Utilities.hh" 9 | #include "Widget.hh" 10 | 11 | namespace ncpp 12 | { 13 | class NCPP_API_EXPORT MultiSelector : public Widget 14 | { 15 | public: 16 | static ncmultiselector_options default_options; 17 | 18 | public: 19 | explicit MultiSelector (Plane *plane, const ncmultiselector_options *opts = nullptr) 20 | : Widget (Utilities::get_notcurses_cpp (plane)) 21 | { 22 | ensure_valid_plane (plane); 23 | common_init (Utilities::to_ncplane (plane), opts); 24 | take_plane_ownership (plane); 25 | } 26 | 27 | explicit MultiSelector (Plane &plane, const ncmultiselector_options *opts = nullptr) 28 | : Widget (Utilities::get_notcurses_cpp (plane)) 29 | { 30 | ensure_valid_plane (plane); 31 | common_init (Utilities::to_ncplane (plane), opts); 32 | take_plane_ownership (plane); 33 | } 34 | 35 | ~MultiSelector () 36 | { 37 | if (!is_notcurses_stopped ()) 38 | ncmultiselector_destroy (multiselector); 39 | } 40 | 41 | bool offer_input (const struct ncinput *ni) const noexcept 42 | { 43 | return ncmultiselector_offer_input (multiselector, ni); 44 | } 45 | 46 | int get_selected (bool *selected, unsigned count) const NOEXCEPT_MAYBE 47 | { 48 | return error_guard (ncmultiselector_selected (multiselector, selected, count), -1); 49 | } 50 | 51 | Plane* get_plane () const noexcept; 52 | 53 | private: 54 | void common_init (ncplane *plane, const ncmultiselector_options *opts) 55 | { 56 | if (plane == nullptr) 57 | throw invalid_argument ("'plane' must be a valid pointer"); 58 | 59 | multiselector = ncmultiselector_create (plane, opts == nullptr ? &default_options : opts); 60 | if (multiselector == nullptr) 61 | throw init_error ("Notcurses failed to create a new multiselector"); 62 | } 63 | 64 | private: 65 | ncmultiselector *multiselector; 66 | }; 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /include/ncpp/NCAlign.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_NCALIGN_HH 2 | #define __NCPP_NCALIGN_HH 3 | 4 | #include 5 | 6 | namespace ncpp 7 | { 8 | enum class NCAlign 9 | { 10 | Left = NCALIGN_LEFT, 11 | Center = NCALIGN_CENTER, 12 | Right = NCALIGN_RIGHT, 13 | }; 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /include/ncpp/NCBox.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_NCBOX_HH 2 | #define __NCPP_NCBOX_HH 3 | 4 | #include 5 | 6 | namespace ncpp 7 | { 8 | struct NCBox 9 | { 10 | static constexpr unsigned MaskTop = NCBOXMASK_TOP; 11 | static constexpr unsigned MaskRight = NCBOXMASK_RIGHT; 12 | static constexpr unsigned MaskBottom = NCBOXMASK_BOTTOM; 13 | static constexpr unsigned MaskLeft = NCBOXMASK_LEFT; 14 | 15 | static constexpr unsigned GradTop = NCBOXGRAD_TOP; 16 | static constexpr unsigned GradRight = NCBOXGRAD_RIGHT; 17 | static constexpr unsigned GradBottom = NCBOXGRAD_BOTTOM; 18 | static constexpr unsigned GradLeft = NCBOXGRAD_LEFT; 19 | 20 | static constexpr unsigned CornerMask = NCBOXCORNER_MASK; 21 | static constexpr unsigned CornerShift = NCBOXCORNER_SHIFT; 22 | }; 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /include/ncpp/NCLogLevel.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_NCLOGLEVEL_HH 2 | #define __NCPP_NCLOGLEVEL_HH 3 | 4 | #include 5 | 6 | namespace ncpp 7 | { 8 | struct NCLogLevel 9 | { 10 | static constexpr ncloglevel_e Silent = NCLOGLEVEL_SILENT; 11 | static constexpr ncloglevel_e Panic = NCLOGLEVEL_PANIC; 12 | static constexpr ncloglevel_e Fatal = NCLOGLEVEL_FATAL; 13 | static constexpr ncloglevel_e Error = NCLOGLEVEL_ERROR; 14 | static constexpr ncloglevel_e Warning = NCLOGLEVEL_WARNING; 15 | static constexpr ncloglevel_e Info = NCLOGLEVEL_INFO; 16 | static constexpr ncloglevel_e Verbose = NCLOGLEVEL_VERBOSE; 17 | static constexpr ncloglevel_e Debug = NCLOGLEVEL_DEBUG; 18 | static constexpr ncloglevel_e Trace = NCLOGLEVEL_TRACE; 19 | }; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /include/ncpp/Palette.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_PALETTE_HH 2 | #define __NCPP_PALETTE_HH 3 | 4 | #include "Root.hh" 5 | #include "_helpers.hh" 6 | 7 | namespace ncpp 8 | { 9 | class NotCurses; 10 | 11 | class NCPP_API_EXPORT Palette : public Root 12 | { 13 | public: 14 | Palette (NotCurses *ncinst = nullptr) 15 | : Root (ncinst) 16 | { 17 | palette = ncpalette_new (get_notcurses ()); 18 | if (palette == nullptr) 19 | throw init_error ("Notcurses failed to create a new palette"); 20 | } 21 | 22 | ~Palette () 23 | { 24 | ncpalette_free (palette); 25 | } 26 | 27 | operator ncpalette* () noexcept 28 | { 29 | return palette; 30 | } 31 | 32 | operator ncpalette const* () const noexcept 33 | { 34 | return palette; 35 | } 36 | 37 | bool set (int idx, int r, int g, int b) const NOEXCEPT_MAYBE 38 | { 39 | return error_guard (ncpalette_set_rgb8 (palette, idx, r, g, b), -1); 40 | } 41 | 42 | bool set (int idx, unsigned rgb) const NOEXCEPT_MAYBE 43 | { 44 | return error_guard (ncpalette_set (palette, idx, rgb), -1); 45 | } 46 | 47 | bool get (int idx, unsigned *r, unsigned *g, unsigned *b) const 48 | { 49 | if (r == nullptr) 50 | throw invalid_argument ("'r' must be a valid pointer"); 51 | if (g == nullptr) 52 | throw invalid_argument ("'g' must be a valid pointer"); 53 | if (b == nullptr) 54 | throw invalid_argument ("'b' must be a valid pointer"); 55 | 56 | return get (idx, *r, *g, *b); 57 | } 58 | 59 | bool get (int idx, unsigned &r, unsigned &g, unsigned &b) const NOEXCEPT_MAYBE 60 | { 61 | return error_guard (ncpalette_get_rgb8 (palette, idx, &r, &g, &b), -1); 62 | } 63 | 64 | private: 65 | ncpalette *palette; 66 | }; 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /include/ncpp/Pile.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_PILE_HH 2 | #define __NCPP_PILE_HH 3 | 4 | #include 5 | #include 6 | 7 | #include "NotCurses.hh" 8 | #include "Plane.hh" 9 | 10 | namespace ncpp 11 | { 12 | class NCPP_API_EXPORT Pile : public Plane 13 | { 14 | public: 15 | Pile (ncplane_options const* nopts, NotCurses* ncinst = nullptr) 16 | : Plane (ncinst) 17 | { 18 | if (nopts == nullptr) { 19 | throw invalid_argument ("'nopts' must be a valid pointer"); 20 | } 21 | 22 | notcurses *n; 23 | if (ncinst == nullptr) { 24 | n = NotCurses::get_instance (); 25 | } else { 26 | n = *ncinst; 27 | } 28 | 29 | ncplane *pile = ncpile_create (n, nopts); 30 | if (pile == nullptr) { 31 | throw init_error ("Notcurses failed to create a new pile"); 32 | } 33 | 34 | set_plane (pile); 35 | } 36 | 37 | bool render () const NOEXCEPT_MAYBE 38 | { 39 | return error_guard (ncpile_render (to_ncplane ()), -1); 40 | } 41 | 42 | bool rasterize () const NOEXCEPT_MAYBE 43 | { 44 | return error_guard (ncpile_rasterize (to_ncplane ()), -1); 45 | } 46 | 47 | bool show () const NOEXCEPT_MAYBE 48 | { 49 | if (!render ()) { 50 | return false; 51 | } 52 | 53 | return rasterize (); 54 | } 55 | 56 | static Plane* top_with (const Plane& plane) noexcept 57 | { 58 | ncplane* ret = ncpile_top (const_cast(plane)); 59 | if (ret == nullptr) { 60 | return nullptr; 61 | } 62 | 63 | return map_plane (ret); 64 | } 65 | 66 | static Plane* bottom_with (const Plane& plane) noexcept 67 | { 68 | ncplane* ret = ncpile_bottom (const_cast(plane)); 69 | if (ret == nullptr) { 70 | return nullptr; 71 | } 72 | 73 | return map_plane (ret); 74 | } 75 | }; 76 | } 77 | #endif 78 | -------------------------------------------------------------------------------- /include/ncpp/Progbar.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_PROGBAR_HH 2 | #define __NCPP_PROGBAR_HH 3 | 4 | #include 5 | #include 6 | 7 | #include "NotCurses.hh" 8 | #include "Plane.hh" 9 | 10 | namespace ncpp 11 | { 12 | class NCPP_API_EXPORT Progbar : public Root 13 | { 14 | public: 15 | Progbar (Plane& n, const ncprogbar_options* opts) 16 | : Root (nullptr) 17 | { 18 | if (opts == nullptr) { 19 | throw invalid_argument ("Argument 'opts' must be a valid pointer"); 20 | } 21 | 22 | progbar = ncprogbar_create (n, opts); 23 | if (progbar == nullptr) { 24 | throw init_error ("Notcurses failed to create ncprogbar"); 25 | } 26 | } 27 | 28 | ~Progbar () 29 | { 30 | if (!is_notcurses_stopped ()) { 31 | ncprogbar_destroy (progbar); 32 | } 33 | } 34 | 35 | Plane* get_plane () const noexcept 36 | { 37 | ncplane *ret = ncprogbar_plane (progbar); 38 | if (ret == nullptr) { 39 | return nullptr; 40 | } 41 | 42 | return Plane::map_plane (ret); 43 | } 44 | 45 | void set_progress (double p) const noexcept 46 | { 47 | ncprogbar_set_progress (progbar, p); 48 | } 49 | 50 | double get_progress () const noexcept 51 | { 52 | return ncprogbar_progress (progbar); 53 | } 54 | 55 | private: 56 | ncprogbar *progbar = nullptr; 57 | }; 58 | } 59 | 60 | #endif // __NCPP_PROGBAR_HH 61 | -------------------------------------------------------------------------------- /include/ncpp/Tablet.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_TABLET_HH 2 | #define __NCPP_TABLET_HH 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "Root.hh" 10 | 11 | namespace ncpp 12 | { 13 | class Plane; 14 | class NotCurses; 15 | 16 | class NCPP_API_EXPORT NcTablet : public Root 17 | { 18 | protected: 19 | explicit NcTablet (nctablet *t, NotCurses *ncinst) 20 | : Root (ncinst), 21 | _tablet (t) 22 | { 23 | if (t == nullptr) 24 | throw invalid_argument ("'t' must be a valid pointer"); 25 | }; 26 | 27 | public: 28 | template 29 | T* get_userptr () const noexcept 30 | { 31 | return static_cast(nctablet_userptr (_tablet)); 32 | } 33 | 34 | operator nctablet* () const noexcept 35 | { 36 | return _tablet; 37 | } 38 | 39 | operator nctablet const* () const noexcept 40 | { 41 | return _tablet; 42 | } 43 | 44 | Plane* get_plane () const noexcept; 45 | static NcTablet* map_tablet (nctablet *t, NotCurses *ncinst = nullptr) noexcept; 46 | 47 | protected: 48 | static void unmap_tablet (NcTablet *p) noexcept; 49 | 50 | nctablet* get_tablet () const noexcept 51 | { 52 | return _tablet; 53 | } 54 | 55 | private: 56 | nctablet *_tablet = nullptr; 57 | static std::map *tablet_map; 58 | static std::mutex tablet_map_mutex; 59 | 60 | friend class NcReel; 61 | }; 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /include/ncpp/TabletCallback.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_TABLET_CALLBACK_HH 2 | #define __NCPP_TABLET_CALLBACK_HH 3 | 4 | namespace ncpp 5 | { 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /include/ncpp/Utilities.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_UTILITIES_HH 2 | #define __NCPP_UTILITIES_HH 3 | 4 | #include 5 | 6 | #include "_helpers.hh" 7 | 8 | namespace ncpp 9 | { 10 | class NotCurses; 11 | class Plane; 12 | class Root; 13 | 14 | class NCPP_API_EXPORT Utilities 15 | { 16 | public: 17 | static ncplane* to_ncplane (const Plane *plane) noexcept; 18 | 19 | static ncplane* to_ncplane (const Plane &plane) noexcept 20 | { 21 | return to_ncplane (&plane); 22 | } 23 | 24 | static NotCurses* get_notcurses_cpp (const Root *o) noexcept; 25 | 26 | static NotCurses* get_notcurses_cpp (const Root &o) noexcept 27 | { 28 | return get_notcurses_cpp (&o); 29 | } 30 | 31 | static NotCurses* get_notcurses_cpp (const Plane *plane) noexcept; 32 | 33 | static NotCurses* get_notcurses_cpp (const Plane &plane) noexcept 34 | { 35 | return get_notcurses_cpp (&plane); 36 | } 37 | }; 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /include/ncpp/Widget.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_WIDGET_HH 2 | #define __NCPP_WIDGET_HH 3 | 4 | #include "Root.hh" 5 | #include "Plane.hh" 6 | 7 | namespace ncpp 8 | { 9 | class NCPP_API_EXPORT Widget : public Root 10 | { 11 | protected: 12 | explicit Widget (NotCurses *ncinst) 13 | : Root (ncinst) 14 | {} 15 | 16 | void ensure_valid_plane (Plane *plane) const 17 | { 18 | if (plane == nullptr) 19 | throw invalid_argument ("'plane' must be a valid pointer"); 20 | ensure_valid_plane (*plane); 21 | } 22 | 23 | void ensure_valid_plane (Plane &plane) const 24 | { 25 | if (!plane.is_valid ()) 26 | throw invalid_argument ("Invalid Plane object passed in 'plane'. Widgets must not reuse the same plane."); 27 | } 28 | 29 | void take_plane_ownership (Plane *plane) const 30 | { 31 | if (plane == nullptr) 32 | return; 33 | 34 | take_plane_ownership (*plane); 35 | } 36 | 37 | void take_plane_ownership (Plane &plane) const 38 | { 39 | plane.release_native_plane (); 40 | } 41 | }; 42 | } 43 | #endif // __NCPP_WIDGET_HH 44 | -------------------------------------------------------------------------------- /include/ncpp/_exceptions.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_EXCEPTIONS_HH 2 | #define __NCPP_EXCEPTIONS_HH 3 | 4 | #include 5 | 6 | #include "_helpers.hh" 7 | 8 | namespace ncpp 9 | { 10 | class NCPP_API_EXPORT init_error : public std::logic_error 11 | { 12 | public: 13 | explicit init_error (const std::string& what_arg) 14 | : logic_error (what_arg) 15 | {} 16 | 17 | explicit init_error (const char* what_arg) 18 | : logic_error (what_arg) 19 | {} 20 | }; 21 | 22 | class NCPP_API_EXPORT invalid_state_error : public std::logic_error 23 | { 24 | public: 25 | explicit invalid_state_error (const std::string& what_arg) 26 | : logic_error (what_arg) 27 | {} 28 | 29 | explicit invalid_state_error (const char* what_arg) 30 | : logic_error (what_arg) 31 | {} 32 | }; 33 | 34 | class NCPP_API_EXPORT invalid_argument : public std::invalid_argument 35 | { 36 | public: 37 | explicit invalid_argument (const std::string& what_arg) 38 | : std::invalid_argument (what_arg) 39 | {} 40 | 41 | explicit invalid_argument (const char* what_arg) 42 | : std::invalid_argument (what_arg) 43 | {} 44 | }; 45 | 46 | class NCPP_API_EXPORT call_error : public std::logic_error 47 | { 48 | public: 49 | explicit call_error (const std::string& what_arg) 50 | : logic_error (what_arg) 51 | {} 52 | 53 | explicit call_error (const char* what_arg) 54 | : logic_error (what_arg) 55 | {} 56 | }; 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /include/ncpp/_flag_enum_operator_helpers.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_FLAG_ENUM_OPERATOR_HELPERS_H 2 | #define __NCPP_FLAG_ENUM_OPERATOR_HELPERS_H 3 | 4 | #include 5 | 6 | #include "_helpers.hh" 7 | 8 | namespace ncpp 9 | { 10 | #define DECLARE_ENUM_FLAG_OPERATORS(__enum_name__) \ 11 | NCPP_API_EXPORT constexpr __enum_name__ operator& (__enum_name__ x, __enum_name__ y) \ 12 | { \ 13 | typedef std::underlying_type<__enum_name__>::type etype; \ 14 | return __enum_name__ (static_cast (x) & static_cast (y)); \ 15 | } \ 16 | NCPP_API_EXPORT constexpr __enum_name__& operator&= (__enum_name__& x, __enum_name__ y) \ 17 | { \ 18 | typedef std::underlying_type<__enum_name__>::type etype; \ 19 | return x = __enum_name__ (static_cast (x) & static_cast (y)); \ 20 | } \ 21 | NCPP_API_EXPORT constexpr __enum_name__ operator| (__enum_name__ x, __enum_name__ y) \ 22 | { \ 23 | typedef std::underlying_type<__enum_name__>::type etype; \ 24 | return __enum_name__ (static_cast (x) | static_cast (y)); \ 25 | } \ 26 | NCPP_API_EXPORT constexpr __enum_name__& operator|= (__enum_name__& x, __enum_name__ y) \ 27 | { \ 28 | typedef std::underlying_type<__enum_name__>::type etype; \ 29 | return x = __enum_name__ (static_cast (x) | static_cast (y)); \ 30 | } \ 31 | NCPP_API_EXPORT constexpr __enum_name__ operator^ (__enum_name__ x, __enum_name__ y) \ 32 | { \ 33 | typedef std::underlying_type<__enum_name__>::type etype; \ 34 | return __enum_name__ (static_cast (x) ^ static_cast (y)); \ 35 | } \ 36 | NCPP_API_EXPORT constexpr __enum_name__& operator^= (__enum_name__& x, __enum_name__ y) \ 37 | { \ 38 | typedef std::underlying_type<__enum_name__>::type etype; \ 39 | return x = __enum_name__ (static_cast (x) ^ static_cast (y)); \ 40 | } \ 41 | NCPP_API_EXPORT constexpr __enum_name__& operator~ (__enum_name__& x) \ 42 | { \ 43 | typedef std::underlying_type<__enum_name__>::type etype; \ 44 | return x = __enum_name__ (~static_cast (x)); \ 45 | } \ 46 | NCPP_API_EXPORT constexpr __enum_name__ operator~ (__enum_name__ x) \ 47 | { \ 48 | typedef std::underlying_type<__enum_name__>::type etype; \ 49 | return __enum_name__ (~static_cast (x)); \ 50 | } 51 | } 52 | #endif 53 | -------------------------------------------------------------------------------- /include/ncpp/_helpers.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_HELPERS_HH 2 | #define __NCPP_HELPERS_HH 3 | 4 | namespace ncpp 5 | { 6 | #define NCPP_LIKELY(expr) (__builtin_expect ((expr) != 0, 1)) 7 | #define NCPP_UNLIKELY(expr) (__builtin_expect ((expr) != 0, 0)) 8 | 9 | #define NCPP_API_EXPORT __attribute__((visibility ("default"))) 10 | #define NCPP_API_LOCAL __attribute__((visibility ("hidden"))) 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /include/ncpp/internal/Helpers.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_INTERNAL_HELPERS_HH 2 | #define __NCPP_INTERNAL_HELPERS_HH 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ncpp::internal 9 | { 10 | class Helpers 11 | { 12 | public: 13 | template 14 | static TValue lookup_map_entry (std::map *&_map, std::mutex &_mutex, TKey _key, std::function create_value) 15 | { 16 | std::lock_guard lock (_mutex); 17 | if (_map == nullptr) { 18 | _map = new std::map (); 19 | } 20 | 21 | TValue ret; 22 | auto entry = _map->find (_key); 23 | if (entry == _map->end ()) { 24 | ret = create_value (_key); 25 | } else { 26 | ret = entry->second; 27 | } 28 | 29 | return ret; 30 | } 31 | 32 | template 33 | static void remove_map_entry (std::map *&_map, std::mutex &_mutex, TKey _key) 34 | { 35 | std::lock_guard lock (_mutex); 36 | if (_map == nullptr) 37 | return; 38 | 39 | auto entry = _map->find (_key); 40 | if (entry == _map->end ()) 41 | return; 42 | 43 | _map->erase (entry); 44 | } 45 | }; 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /include/ncpp/ncpp.hh: -------------------------------------------------------------------------------- 1 | #ifndef __NCPP_NCPP_HH 2 | #define __NCPP_NCPP_HH 3 | 4 | #include 5 | 6 | #include "NotCurses.hh" 7 | 8 | namespace ncpp 9 | { 10 | 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /include/notcurses/ncport.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_NCPORT 2 | #define NOTCURSES_NCPORT 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | // Platform-dependent preprocessor material (includes and definitions) needed 9 | // to compile against Notcurses. A critical definition is htole(), which forces 10 | // 32-bit values to little-endian (as used in the nccell gcluster field). This 11 | // ought be defined so that it's a a no-op on little-endian builds. 12 | 13 | #ifndef __MINGW32__ // All but Windows 14 | #include 15 | #endif 16 | 17 | #if defined(__linux__) // Linux 18 | #include 19 | #define htole(x) (__bswap_32(htonl(x))) 20 | #elif defined(__APPLE__) // macOS 21 | #include 22 | #define htole(x) (OSSwapInt32(htonl(x))) 23 | #elif defined(__gnu_hurd__) // Hurd 24 | #include 25 | #include 26 | #define htole(x) (__bswap_32(htonl(x))) 27 | #define wcwidth(w) 1 // FIXME lol, no 28 | #define wcswidth(w, s) (int)(wcslen(w)) // FIXME lol, no 29 | #elif defined(__MINGW32__) // Windows 30 | #include 31 | #define wcwidth(w) 1 // FIXME lol, no 32 | #define wcswidth(w, s) (int)(wcslen(w)) // FIXME lol, no 33 | #define htole(x) (x) // FIXME are all windows installs LE? ugh 34 | #else // BSDs 35 | #include 36 | #define htole(x) (bswap32(htonl(x))) 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | } // extern "C" 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | .mypy_cache 2 | .vscode 3 | *.pyc 4 | __pycache__ 5 | build 6 | dev* 7 | strace*.txt 8 | notcurses/*.so 9 | -------------------------------------------------------------------------------- /python/.readthedocs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # .readthedocs.yml 3 | # Read the Docs configuration file 4 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 5 | 6 | # Required 7 | version: 2 8 | 9 | # Build documentation in the docs/ directory with Sphinx 10 | sphinx: 11 | configuration: docs/conf.py 12 | 13 | # Optionally build your docs in additional formats such as PDF 14 | formats: 15 | - pdf 16 | - epub 17 | 18 | # Set the version of Python 19 | python: 20 | version: 3.8 21 | -------------------------------------------------------------------------------- /python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FindPkgConfig) 2 | pkg_search_module(PYTHON3 REQUIRED python3) 3 | 4 | set(NOTCURSES_PYTHON_SRC 5 | notcurses/context.c 6 | notcurses/misc.c 7 | notcurses/channels.c 8 | notcurses/main.c 9 | notcurses/notcurses-python.h 10 | notcurses/plane.c 11 | ) 12 | 13 | add_library( 14 | dummy_python MODULE 15 | ${NOTCURSES_PYTHON_SRC} 16 | ) 17 | 18 | target_include_directories( 19 | dummy_python 20 | PRIVATE ${PYTHON3_INCLUDE_DIRS} 21 | PRIVATE "${PROJECT_SOURCE_DIR}/include" 22 | ) 23 | 24 | target_link_libraries( 25 | dummy_python 26 | PRIVATE 27 | notcurses 28 | ) 29 | 30 | target_compile_options( 31 | dummy_python 32 | PRIVATE -Wall -Wextra 33 | ) 34 | -------------------------------------------------------------------------------- /python/docs/conf.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from sys import path 18 | from os.path import abspath 19 | 20 | project = 'notcurses' 21 | author = 'igo95862' 22 | source_suffix = '.rst' 23 | extensions = ['sphinx.ext.autodoc'] 24 | 25 | path.append(abspath('..')) 26 | -------------------------------------------------------------------------------- /python/docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Notcurses python documentation! 2 | ======================================================= 3 | 4 | Notcurses python binds documentation 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents: 9 | 10 | nc_context 11 | nc_plane 12 | nc_input 13 | nc_direct 14 | nc_misc 15 | 16 | 17 | Indices and tables 18 | ================== 19 | 20 | * :ref:`genindex` 21 | * :ref:`modindex` 22 | * :ref:`search` -------------------------------------------------------------------------------- /python/docs/nc_context.rst: -------------------------------------------------------------------------------- 1 | Notcurses Context documentation 2 | =============================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | .. autofunction:: notcurses.get_std_plane 9 | 10 | .. autoclass:: notcurses.NotcursesContext 11 | :members: 12 | :special-members: __init__ 13 | -------------------------------------------------------------------------------- /python/docs/nc_direct.rst: -------------------------------------------------------------------------------- 1 | NcDirect documentation 2 | ====================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | .. autoclass:: notcurses.NcDirect 9 | :members: 10 | :special-members: __init__ 11 | -------------------------------------------------------------------------------- /python/docs/nc_input.rst: -------------------------------------------------------------------------------- 1 | NcInput documentation 2 | ====================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | .. autoclass:: notcurses.NcInput 9 | :members: 10 | 11 | .. autoclass:: notcurses.NcInputCodes 12 | :members: 13 | -------------------------------------------------------------------------------- /python/docs/nc_misc.rst: -------------------------------------------------------------------------------- 1 | Notcurses miscellaneous classes 2 | =============================== 3 | 4 | .. autoclass:: notcurses.NcAlign 5 | :members: 6 | 7 | .. autoclass:: notcurses.NcChannels 8 | :members: 9 | :special-members: __init__ 10 | -------------------------------------------------------------------------------- /python/docs/nc_plane.rst: -------------------------------------------------------------------------------- 1 | NcPlane documentation 2 | ====================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | .. autoclass:: notcurses.NcPlane 9 | :members: 10 | :special-members: __init__ 11 | -------------------------------------------------------------------------------- /python/examples/000-print-version.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | from notcurses import notcurses_version 17 | 18 | print(notcurses_version()) 19 | -------------------------------------------------------------------------------- /python/examples/001-init-notcurses.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | from time import sleep 17 | 18 | from notcurses import Notcurses 19 | 20 | Notcurses() 21 | 22 | sleep(1) 23 | -------------------------------------------------------------------------------- /python/examples/002-hello-world.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from time import sleep 18 | 19 | from notcurses import Notcurses 20 | 21 | nc = Notcurses() 22 | 23 | stdplane = nc.stdplane() 24 | stdplane.putstr("Hello, World!") 25 | 26 | nc.render() 27 | 28 | sleep(3) 29 | -------------------------------------------------------------------------------- /python/examples/003-color-example.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from time import sleep 18 | 19 | from notcurses import Notcurses 20 | 21 | 22 | nc = Notcurses() 23 | 24 | stdplane = nc.stdplane() 25 | stdplane.set_bg_rgb8_clipped(0, 0, 255) 26 | stdplane.set_fg_rgb8_clipped(255, 0, 0) 27 | stdplane.putstr_yx(0, 0, "Red on blue") 28 | 29 | stdplane.set_bg_rgb8(0, 255, 0) 30 | stdplane.set_fg_rgb8(255, 255, 255) 31 | stdplane.putstr_yx(1, 0, "White on green") 32 | 33 | stdplane.set_bg_rgb8(0, 0, 0) 34 | stdplane.set_fg_rgb8(255, 0, 255) 35 | stdplane.putstr_yx(2, 0, "Purple on black") 36 | 37 | nc.render() 38 | 39 | sleep(5) 40 | -------------------------------------------------------------------------------- /python/examples/004-dimensions.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from time import sleep 18 | from notcurses import Notcurses 19 | 20 | nc = Notcurses() 21 | plane = nc.stdplane() 22 | 23 | y_dimension, x_dimension = plane.dim_yx() 24 | for y in range(y_dimension): 25 | for x in range(x_dimension): 26 | y_frac = round(y / y_dimension * 256) 27 | x_frac = round(x / x_dimension * 256) 28 | plane.set_fg_rgb8(128, y_frac, x_frac) 29 | plane.set_bg_rgb8(x_frac, 128, y_frac) 30 | plane.putstr_yx(y, x, 'X') 31 | 32 | nc.render() 33 | sleep(5) 34 | 35 | -------------------------------------------------------------------------------- /python/examples/006-input-tester.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from notcurses import Notcurses 18 | 19 | nc = Notcurses() 20 | std_plane = nc.stdplane() 21 | std_plane.putstr("Enter string!") 22 | 23 | nc.render() 24 | nc.mice_enable() 25 | 26 | while True: 27 | # Get an input event and print its properties 28 | inp = nc.get_blocking() 29 | std_plane.erase() 30 | std_plane.putstr_yx(1, 4, f"Code point: {hex(inp.id)}") 31 | std_plane.putstr_yx(2, 4, f"Y pos: {inp.y}") 32 | std_plane.putstr_yx(3, 4, f"X pos: {inp.x}") 33 | std_plane.putstr_yx(4, 4, f"UTF-8: {inp.utf8!r}") 34 | std_plane.putstr_yx(5, 4, f"Event type: {inp.evtype}") 35 | std_plane.putstr_yx(6, 4, f"Modifiers: {bin(inp.modifiers)}") 36 | std_plane.putstr_yx(7, 4, f"Y pixel offset: {inp.ypx}") 37 | std_plane.putstr_yx(8, 4, f"X pixel offset: {inp.xpx}") 38 | std_plane.putstr_yx(10, 4, "Press CTRL+C to exit.") 39 | 40 | nc.render() 41 | -------------------------------------------------------------------------------- /python/examples/007-plane_split.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | from time import sleep 19 | 20 | from notcurses import Notcurses 21 | 22 | nc = Notcurses() 23 | 24 | stdplane = nc.stdplane() 25 | 26 | sub_plane_left = stdplane.create( 27 | rows=5, 28 | cols=5, 29 | ) 30 | 31 | sub_plane_right = stdplane.create( 32 | x_pos=(stdplane.dim_x() // 2), 33 | rows=5, 34 | cols=5, 35 | ) 36 | 37 | sub_plane_left.set_fg_rgb8(0, 255, 0) 38 | sub_plane_left.putstr("Left") 39 | 40 | sub_plane_right.set_fg_rgb8(255, 0, 0) 41 | sub_plane_right.putstr("Right") 42 | 43 | nc.render() 44 | 45 | sleep(3) 46 | -------------------------------------------------------------------------------- /python/examples/008-put-lines.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Copyright 2020 igo95862 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | from time import sleep 19 | 20 | from notcurses import Notcurses 21 | 22 | nc = Notcurses() 23 | 24 | stdplane = nc.stdplane() 25 | 26 | test_str = '''Sapiente quaerat expedita repellendus ea quae. Ut enim natus iure laborum. Assumenda sed placeat provident similique cum quidem. Sit voluptas facilis vitae culpa asperiores eos neque. 27 | Aspernatur rerum quae minus natus. Vero autem suscipit nisi eligendi dolorum sed vero. Illum odio repudiandae odit in voluptas reiciendis amet. 28 | Sunt ea hic repudiandae beatae. Nisi asperiores aut commodi dolorem itaque illum sunt eum. Aperiam illo ratione in. Eaque perspiciatis repellat minima culpa et consequatur voluptatem voluptas. 29 | Laboriosam expedita ut enim velit occaecati qui neque. Et voluptatem eligendi harum sed ducimus enim culpa. Quia expedita distinctio provident qui et dolorem placeat. Provident aut corporis laudantium quo. 30 | Dolores quaerat sint dolorum. Corrupti temporibus nam corrupti. Iusto non perspiciatis et quisquam minima nesciunt quia esse. 31 | ''' 32 | 33 | wr = stdplane.puttext(-1, 0, test_str) 34 | 35 | nc.render() 36 | 37 | sleep(3) 38 | -------------------------------------------------------------------------------- /python/examples/009-box.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | import notcurses as nc 3 | 4 | notcurses = nc.Notcurses() 5 | plane = notcurses.stdplane() 6 | 7 | BOX_CHARS = ( 8 | nc.NCBOXASCII, 9 | nc.NCBOXDOUBLE, 10 | nc.NCBOXHEAVY, 11 | nc.NCBOXLIGHT, 12 | nc.NCBOXOUTER, 13 | nc.NCBOXROUND, 14 | ) 15 | 16 | COLORS = ( 17 | (None, None), 18 | (None, nc.rgb(128, 128, 128)), # default on grey 19 | (nc.rgb(255, 0, 0), None), # red on default 20 | (nc.rgb(0, 255, 0), nc.rgb(0, 0, 255)), # green on blue 21 | ) 22 | 23 | SY = 7 24 | SX = 10 25 | 26 | for y, (fg, bg) in enumerate(COLORS): 27 | for x, box_chars in enumerate(BOX_CHARS): 28 | plane.cursor_move_yx(y * SY + 1, x * SX + 1); 29 | nc.box( 30 | plane, (y + 1) * SY - 1, (x + 1) * SX - 1, 31 | box_chars, 32 | fg=fg, bg=bg, 33 | # ctlword=0x1f9 34 | ) 35 | 36 | notcurses.render() 37 | sleep(5) 38 | -------------------------------------------------------------------------------- /python/notcurses/misc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | /* 3 | Copyright 2020, 2021 igo95862 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | #include "notcurses-python.h" 19 | 20 | static PyObject * 21 | python_notcurses_version(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) 22 | { 23 | const char *verstion_str = notcurses_version(); 24 | return PyUnicode_FromString(verstion_str); 25 | } 26 | 27 | static PyObject * 28 | python_notcurses_version_components(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) 29 | { 30 | int major, minor, patch, tweak = {0}; 31 | 32 | notcurses_version_components(&major, &minor, &patch, &tweak); 33 | 34 | return Py_BuildValue("iiii", major, minor, patch, tweak); 35 | } 36 | 37 | static PyObject * 38 | python_ncstrwidth(PyObject *Py_UNUSED(self), PyObject *args) 39 | { 40 | const char *s = NULL; 41 | 42 | GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "s", &s, NULL, NULL)); 43 | 44 | return Py_BuildValue("i", ncstrwidth(s, NULL, NULL)); 45 | } 46 | 47 | PyMethodDef MiscFunctions[] = { 48 | {"notcurses_version", (PyCFunction)python_notcurses_version, METH_NOARGS, "Get a human-readable string describing the running Notcurses version."}, 49 | {"notcurses_version_components", (PyCFunction)python_notcurses_version_components, METH_NOARGS, "Get a tuple of major, minor, patch, tweak integer of the running Notcurses version."}, 50 | {"ncstrwidth", (PyCFunction)python_ncstrwidth, METH_VARARGS, "Returns the number of columns occupied by a string, or -1 if a non-printable/illegal character is encountered."}, 51 | {NULL, NULL, 0, NULL}, 52 | }; 53 | -------------------------------------------------------------------------------- /python/notcurses/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dankamongmen/notcurses/94e36ccc32ed65aa394a895d53c46081aaef4450/python/notcurses/py.typed -------------------------------------------------------------------------------- /src/demo/qrcode.c: -------------------------------------------------------------------------------- 1 | #include "demo.h" 2 | 3 | int qrcode_demo(struct notcurses* nc, uint64_t startns){ 4 | (void)startns; 5 | if(!notcurses_canutf8(nc)){ 6 | return 0; 7 | } 8 | #ifdef USE_QRCODEGEN 9 | char data[128]; 10 | unsigned dimy, dimx; 11 | struct ncplane *stdn = notcurses_stddim_yx(nc, &dimy, &dimx); 12 | ncplane_erase(stdn); 13 | struct ncplane* n = ncplane_dup(stdn, NULL); 14 | for(int i = 0 ; i < 1024 ; ++i){ 15 | ncplane_erase(n); 16 | size_t len = rand() % sizeof(data) + 1; 17 | size_t done = 0; 18 | // done this tedious way because getrand() doesn't exist on freebsd 11 19 | while(done < len){ 20 | long r = rand(); 21 | memcpy(data + done, &r, sizeof(r)); 22 | done += sizeof(r); 23 | } 24 | ncplane_home(n); 25 | unsigned y = dimy, x = dimx; 26 | ncplane_home(n); 27 | int qlen = ncplane_qrcode(n, &y, &x, data, len); 28 | if(qlen > 0){ // FIXME can fail due to being too large for display; distinguish this case 29 | ncplane_move_yx(n, (dimy - y) / 2, (dimx - x) / 2); 30 | ncplane_home(n); 31 | ncplane_set_fg_rgb8(n, rand() % 255 + 1, rand() % 255 + 1, rand() % 255 + 1); 32 | DEMO_RENDER(nc); 33 | } 34 | } 35 | ncplane_mergedown_simple(n, stdn); // leave the last one on-screen 36 | ncplane_destroy(n); 37 | #endif 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /src/fetch/ncart.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | const char* get_neofetch_art(const char* oskey); 4 | -------------------------------------------------------------------------------- /src/lib/automaton.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_AUTOMATON 2 | #define NOTCURSES_AUTOMATON 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | struct ncinput; 11 | struct esctrie; 12 | struct inputctx; 13 | 14 | typedef int (*triefunc)(struct inputctx*); 15 | 16 | // the state necessary for matching input against our automaton of control 17 | // sequences. we *do not* match the bulk UTF-8 input. we match online (i.e. 18 | // we can be passed a byte at a time). initialize with all zeroes. 19 | typedef struct automaton { 20 | unsigned escapes; // head Esc node of trie 21 | int used; // bytes consumed thus far 22 | int instring; // are we in an ST-terminated string? 23 | unsigned state; 24 | const unsigned char* matchstart; // beginning of active match 25 | // we keep a node pool not to save time when allocating, but because 26 | // trying to free the automaton without reference counting otherwise 27 | // sucks worse than three bitches in a bitchboat. 28 | unsigned poolsize; 29 | unsigned poolused; 30 | struct esctrie* nodepool; 31 | } automaton; 32 | 33 | // wipe out all storage internal to |a| (but not |a| itself). 34 | void input_free_esctrie(automaton *a); 35 | 36 | int inputctx_add_input_escape(automaton* a, const char* esc, 37 | uint32_t special, unsigned modifiers); 38 | 39 | int inputctx_add_cflow(automaton* a, const char* csi, triefunc fxn) 40 | __attribute__ ((nonnull (1, 2))); 41 | 42 | int walk_automaton(automaton* a, struct inputctx* ictx, unsigned candidate, 43 | struct ncinput* ni) 44 | __attribute__ ((nonnull (1, 2, 4))); 45 | 46 | uint32_t esctrie_id(const struct esctrie* e); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/lib/banner.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_BANNER 2 | #define NOTCURSES_BANNER 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | struct fbuf; 9 | struct notcurses; 10 | 11 | int init_banner(const struct notcurses* nc, struct fbuf* f); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/lib/blit.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_BLIT 2 | #define NOTCURSES_BLIT 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | struct ncplane; 9 | struct blitterargs; 10 | 11 | // scaledy and scaledx are output geometry from scaling; data is output data 12 | // from scaling. we might actually need more pixels due to framing concerns, 13 | // in which case just assume transparent input pixels where needed. 14 | typedef int (*ncblitter)(struct ncplane* n, int linesize, const void* data, 15 | int scaledy, int scaledx, const struct blitterargs* bargs); 16 | 17 | void set_pixel_blitter(ncblitter blitfxn); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/lib/blitset.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_BLITSET 2 | #define NOTCURSES_BLITSET 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "blit.h" 9 | 10 | // number of pixels that map to a single cell, height-wise 11 | static inline int 12 | encoding_y_scale(const tinfo* tcache, const struct blitset* bset) { 13 | if(bset->geom == NCBLIT_PIXEL){ 14 | return tcache->cellpxy; 15 | } 16 | return bset->height; 17 | } 18 | 19 | // number of pixels that map to a single cell, width-wise 20 | static inline int 21 | encoding_x_scale(const tinfo* tcache, const struct blitset* bset) { 22 | if(bset->geom == NCBLIT_PIXEL){ 23 | return tcache->cellpxx; 24 | } 25 | return bset->width; 26 | } 27 | 28 | // Expand NCBLIT_DEFAULT for media blitting, based on environment. We never 29 | // use NCBLIT_PIXEL for NCBLIT_DEFAULT, though maybe this ought change. 30 | static inline ncblitter_e 31 | rgba_blitter_default(const tinfo* tcache, ncscale_e scale){ 32 | if(!tcache->caps.utf8){ 33 | return NCBLIT_1x1; // only one that works in ASCII 34 | } 35 | if(scale == NCSCALE_NONE || scale == NCSCALE_SCALE){ 36 | return NCBLIT_2x1; 37 | } 38 | if(tcache->caps.octants){ 39 | return NCBLIT_4x2; 40 | } 41 | if(tcache->caps.sextants){ 42 | return NCBLIT_3x2; 43 | } 44 | if(tcache->caps.quadrants){ 45 | return NCBLIT_2x2; 46 | } 47 | return NCBLIT_2x1; 48 | } 49 | 50 | static inline ncblitter_e 51 | ncplot_defblitter(const notcurses* nc){ 52 | if(notcurses_canutf8(nc)){ 53 | return NCBLIT_8x1; 54 | } 55 | return NCBLIT_1x1; 56 | } 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/lib/debug.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | 3 | ncloglevel_e loglevel = NCLOGLEVEL_SILENT; 4 | 5 | void notcurses_debug(const notcurses* nc, FILE* debugfp){ 6 | fbuf f; 7 | if(fbuf_init_small(&f)){ 8 | return; 9 | } 10 | notcurses_debug_fbuf(nc, &f); 11 | fbuf_finalize(&f, debugfp); 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/gpm.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_GPM 2 | #define NOTCURSES_GPM 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | // internal header, not installed 9 | 10 | struct tinfo; 11 | struct ncinput; 12 | 13 | // GPM ("General Purpose Mouse") provides an interface to mice in the Linux 14 | // and FreeBSD consoles. The gpm server must be running; we do not attempt to 15 | // start it. We must have been built with -DUSE_GPM. 16 | 17 | // Returns the poll()able file descriptor associated with gpm, or -1 on failure. 18 | int gpm_connect(struct tinfo* ti); 19 | 20 | // Read from the gpm connection, which ought have been poll()ed. Translates 21 | // the libgpm input to an ncinput. 22 | int gpm_read(struct tinfo* ti, struct ncinput* ni); 23 | 24 | int gpm_close(struct tinfo* ti); 25 | 26 | // Returns a library-owned pointer to the libgpm client version. 27 | const char* gpm_version(void); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/lib/linux.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_LINUX 2 | #define NOTCURSES_LINUX 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | struct tinfo; 12 | 13 | // is this a linux virtual console? 14 | bool is_linux_console(int fd); 15 | 16 | // attempt to reprogram the console font, if necessary, to include all the 17 | // quadrant glyphs (which include the halfblocks). *|halfblocks| will be true 18 | // if the halfblocks are available, whether they required a reprogramming or 19 | // not. *|quadrants| will be true if the quadrants are available, whether that 20 | // required a reprogramming or not. 21 | // note that reprogramming the font drops any existing graphics from the 22 | // framebuffer. if ti has mapped the framebuffer, it will be copied and 23 | // unmapped before we reprogram. after reprogramming, it is remapped, and 24 | // the old contents are copied in, then freed. there will be an unavoidable 25 | // flicker while this happens. 26 | int reprogram_console_font(struct tinfo* ti, unsigned no_font_changes, 27 | bool* halfblocks, bool* quadrants); 28 | 29 | // if is_linux_console() returned true, call this to determine whether it is 30 | // a drawable framebuffer console. do not call if not a verified console! 31 | bool is_linux_framebuffer(struct tinfo* ti); 32 | 33 | // call only on an fd where is_linux_framebuffer() returned true. gets the 34 | // pixel geometry for the visual area. 35 | int get_linux_fb_pixelgeom(struct tinfo* ti, unsigned* ypix, unsigned *xpix); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/lib/logging.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_LOGGING 2 | #define NOTCURSES_LOGGING 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | // logging 9 | extern ncloglevel_e loglevel; 10 | 11 | static inline void nclog(const char* fmt, ...) 12 | __attribute__ ((format (printf, 1, 2))); 13 | 14 | static inline void 15 | nclog(const char* fmt, ...){ 16 | va_list va; 17 | va_start(va, fmt); 18 | vfprintf(stderr, fmt, va); 19 | va_end(va); 20 | } 21 | 22 | #define logpanic(fmt, ...) do{ \ 23 | if(loglevel >= NCLOGLEVEL_PANIC){ \ 24 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 25 | } while(0); 26 | 27 | #define logfatal(fmt, ...) do{ \ 28 | if(loglevel >= NCLOGLEVEL_FATAL){ \ 29 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 30 | } while(0); 31 | 32 | #define logerror(fmt, ...) do{ \ 33 | if(loglevel >= NCLOGLEVEL_ERROR){ \ 34 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 35 | } while(0); 36 | 37 | #define logwarn(fmt, ...) do{ \ 38 | if(loglevel >= NCLOGLEVEL_WARNING){ \ 39 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 40 | } while(0); 41 | 42 | #define loginfo(fmt, ...) do{ \ 43 | if(loglevel >= NCLOGLEVEL_INFO){ \ 44 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 45 | } while(0); 46 | 47 | #define logverbose(fmt, ...) do{ \ 48 | if(loglevel >= NCLOGLEVEL_VERBOSE){ \ 49 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 50 | } while(0); 51 | 52 | #define logdebug(fmt, ...) do{ \ 53 | if(loglevel >= NCLOGLEVEL_DEBUG){ \ 54 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 55 | } while(0); 56 | 57 | #define logtrace(fmt, ...) do{ \ 58 | if(loglevel >= NCLOGLEVEL_TRACE){ \ 59 | nclog("%s:%d:" fmt NL, __func__, __LINE__, ##__VA_ARGS__); } \ 60 | } while(0); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/lib/mice.c: -------------------------------------------------------------------------------- 1 | #include "internal.h" 2 | 3 | int mouse_setup(tinfo* ti, unsigned eventmask){ 4 | if(ti->qterm == TERMINAL_LINUX){ 5 | if(eventmask == 0){ 6 | if(ti->gpmfd < 0){ 7 | return 0; 8 | } 9 | ti->gpmfd = -1; 10 | return gpm_close(ti); 11 | } 12 | if(ti->gpmfd < 0){ 13 | // FIXME pass in eventmask 14 | if((ti->gpmfd = gpm_connect(ti)) < 0){ 15 | return -1; 16 | } 17 | } 18 | return 0; 19 | } 20 | if(ti->ttyfd < 0){ 21 | logerror("no tty, not emitting mouse control\n"); 22 | return -1; 23 | } 24 | // we'll need to fill in 'h' vs 'l' for both, and the event mode 25 | char command = 'h'; 26 | // we have to choose one event mode, where all > drag > button > none. 27 | // if user wants *only* move and not button, we'll need filter those FIXME. 28 | if(eventmask & NCMICE_MOVE_EVENT){ 29 | ti->mouseproto = '3'; // SET_ALL_EVENT_MOUSE 30 | }else if(eventmask & NCMICE_DRAG_EVENT){ 31 | ti->mouseproto = '2'; // SET_BTN_EVENT_MOUSE 32 | }else if(eventmask & NCMICE_BUTTON_EVENT){ 33 | ti->mouseproto = '0'; // SET_X11_MOUSE_PROT 34 | }else if(eventmask == 0){ 35 | if(ti->mouseproto == 0){ 36 | return 0; 37 | } 38 | command = 'l'; 39 | } 40 | // Sets the shift-escape option, allowing shift+mouse to override the standard 41 | // mouse protocol (mainly so copy-and-paste can still be performed). 42 | #define XTSHIFTESCAPE "\x1b[>1s" 43 | char* mousecmd; 44 | if(ti->pixelmice){ 45 | static char m[] = XTSHIFTESCAPE "\x1b[?100x;" SET_PIXEL_MOUSE_PROT "x"; 46 | mousecmd = m; 47 | }else{ 48 | static char m[] = XTSHIFTESCAPE "\x1b[?100x;" SET_SGR_MOUSE_PROT "x"; 49 | mousecmd = m; 50 | } 51 | mousecmd[11] = ti->mouseproto; 52 | mousecmd[17] = command; 53 | if(command == 'l'){ 54 | ti->mouseproto = 0; 55 | } 56 | return tty_emit(mousecmd, ti->ttyfd); 57 | #undef XTSHIFTESCAPE 58 | } 59 | -------------------------------------------------------------------------------- /src/lib/render.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_RENDER 2 | #define NOTCURSES_RENDER 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | extern sig_atomic_t sigcont_seen_for_render; 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/lib/unixsig.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_UNIXSIG 2 | #define NOTCURSES_UNIXSIG 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | int setup_signals(void* nc, bool no_quit_sigs, bool no_winch_sig, 11 | int(*handler)(void*, void**, int)); 12 | 13 | // call at the beginning of shutdown (we don't want to run fatal signal 14 | // handlers during shutdown!). altstack is written to be freed late. 15 | int drop_signals(void* nc, void** altstack); 16 | 17 | // block a few signals for the duration of a write to the terminal. 18 | int block_signals(sigset_t* old_blocked_signals); 19 | int unblock_signals(const sigset_t* old_blocked_signals); 20 | 21 | // the alternate signal stack is a thread property; any other threads we 22 | // create ought go ahead and install the same alternate signal stack. 23 | void setup_alt_sig_stack(void); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/lib/visual-details.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_VISUAL_DETAILS 2 | #define NOTCURSES_VISUAL_DETAILS 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "builddef.h" 13 | 14 | struct blitset; 15 | struct ncplane; 16 | struct sprixel; 17 | struct ncvisual_details; 18 | 19 | // an ncvisual is essentially just an unpacked RGBA bitmap, created by 20 | // reading media from disk, supplying RGBA pixels directly in memory, or 21 | // synthesizing pixels from a plane. 22 | typedef struct ncvisual { 23 | struct ncvisual_details* details;// implementation-specific details 24 | uint32_t* data; // (scaled) RGBA image data, rowstride bytes per row 25 | unsigned pixx, pixy; // pixel geometry, *not* cell geometry 26 | // lines are sometimes padded. this many true bytes per row in data. 27 | unsigned rowstride; 28 | bool owndata; // we own data iff owndata == true 29 | } ncvisual; 30 | 31 | static inline void 32 | ncvisual_set_data(ncvisual* ncv, void* data, bool owned){ 33 | //fprintf(stderr, "replacing %p with %p (%u -> %u)\n", ncv->data, data, ncv->owndata, owned); 34 | if(ncv->owndata){ 35 | if(data != ncv->data){ 36 | free(ncv->data); 37 | } 38 | } 39 | ncv->data = (uint32_t*)data; 40 | ncv->owndata = owned; 41 | } 42 | 43 | // shrink one dimension to retrieve the original aspect ratio 44 | static inline void 45 | scale_visual(const ncvisual* ncv, unsigned* disprows, unsigned* dispcols){ 46 | float xratio = (float)(*dispcols) / ncv->pixx; 47 | if(xratio * ncv->pixy > *disprows){ 48 | xratio = (float)(*disprows) / ncv->pixy; 49 | } 50 | *disprows = xratio * (ncv->pixy); 51 | *dispcols = xratio * (ncv->pixx); 52 | } 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/lib/windows.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_WINDOWS 2 | #define NOTCURSES_WINDOWS 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | struct tinfo; 9 | 10 | // ti has been memset to all zeroes. windows configuration is static. 11 | int prepare_windows_terminal(struct tinfo* ti, size_t* tablelen, 12 | size_t* tableused); 13 | 14 | #ifdef __cplusplus 15 | } 16 | #endif 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/libcpp/FDPlane.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace ncpp; 4 | 5 | ncfdplane_options FDPlane::default_options = { 6 | nullptr, // curry 7 | false, // follow 8 | 0, // flags 9 | }; 10 | -------------------------------------------------------------------------------- /src/libcpp/Menu.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ncpp; 5 | 6 | ncmenu_options Menu::default_options = { 7 | /* sections */ nullptr, 8 | /* sectioncount */ 0, 9 | /* headerchannels */ 0, 10 | /* sectionchannels */ 0, 11 | /* flags */ 0, 12 | }; 13 | 14 | Plane* Menu::get_plane () const noexcept 15 | { 16 | return Plane::map_plane (ncmenu_plane (menu)); 17 | } 18 | -------------------------------------------------------------------------------- /src/libcpp/MultiSelector.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ncpp; 5 | 6 | ncmultiselector_options MultiSelector::default_options = { 7 | /* title */ nullptr, 8 | /* secondary */ nullptr, 9 | /* footer */ nullptr, 10 | /* items */ nullptr, 11 | /* maxdisplay */ 0, 12 | /* opchannels */ 0, 13 | /* descchannels */ 0, 14 | /* titlechannels */ 0, 15 | /* footchannels */ 0, 16 | /* boxchannels */ 0, 17 | /* flags */ 0, 18 | }; 19 | 20 | Plane* MultiSelector::get_plane () const noexcept 21 | { 22 | return Plane::map_plane (ncmultiselector_plane (multiselector)); 23 | } 24 | -------------------------------------------------------------------------------- /src/libcpp/NotCurses.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ncpp; 5 | 6 | notcurses_options NotCurses::default_notcurses_options = { 7 | /* termtype */ nullptr, 8 | /* loglevel */ NCLogLevel::Silent, 9 | /* margin_t */ 0, 10 | /* margin_r */ 0, 11 | /* margin_b */ 0, 12 | /* margin_l */ 0, 13 | /* flags */ 0, 14 | }; 15 | 16 | NotCurses *NotCurses::_instance = nullptr; 17 | std::mutex NotCurses::init_mutex; 18 | 19 | NotCurses::~NotCurses () 20 | { 21 | const std::lock_guard lock (init_mutex); 22 | 23 | if (nc == nullptr) 24 | return; 25 | 26 | notcurses_stop (nc); 27 | if (_instance == this) 28 | _instance = nullptr; 29 | } 30 | 31 | NotCurses::NotCurses (const notcurses_options &nc_opts, FILE *fp) 32 | : Root (nullptr) 33 | { 34 | const std::lock_guard lock (init_mutex); 35 | 36 | nc = notcurses_init (&nc_opts, fp); 37 | if (nc == nullptr) 38 | throw init_error ("notcurses failed to initialize"); 39 | if (_instance == nullptr) 40 | _instance = this; 41 | } 42 | 43 | Plane* NotCurses::get_top () noexcept 44 | { 45 | ncplane *top = notcurses_top (nc); 46 | if (top == nullptr) 47 | return nullptr; 48 | 49 | return Plane::map_plane (top); 50 | } 51 | 52 | Plane* NotCurses::get_bottom () noexcept 53 | { 54 | ncplane *bottom = notcurses_bottom (nc); 55 | if (bottom == nullptr) 56 | return nullptr; 57 | 58 | return Plane::map_plane (bottom); 59 | } 60 | 61 | // This is potentially dangerous, but alas necessary. It can cause other calls 62 | // here to fail in a bad way, but we need a way to report errors to 63 | // std{out,err} in case of failure and that will work only if notcurses is 64 | // stopped, so... 65 | bool NotCurses::stop () 66 | { 67 | if (nc == nullptr) 68 | throw invalid_state_error (ncpp_invalid_state_message); 69 | 70 | bool ret = !notcurses_stop (nc); 71 | nc = nullptr; 72 | 73 | const std::lock_guard lock (init_mutex); 74 | if (_instance == this) 75 | _instance = nullptr; 76 | 77 | return ret; 78 | } 79 | -------------------------------------------------------------------------------- /src/libcpp/Plane.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace ncpp; 6 | 7 | std::map *Plane::plane_map = nullptr; 8 | std::mutex Plane::plane_map_mutex; 9 | 10 | Plane* Plane::map_plane (ncplane *ncp, Plane *associated_plane) noexcept 11 | { 12 | if (ncp == nullptr) 13 | return nullptr; 14 | 15 | return internal::Helpers::lookup_map_entry ( 16 | plane_map, 17 | plane_map_mutex, 18 | ncp, 19 | [&] (ncplane *_ncp) -> Plane* { 20 | return associated_plane == nullptr ? new Plane (_ncp) : associated_plane; 21 | } 22 | ); 23 | } 24 | 25 | void Plane::unmap_plane (Plane *p) noexcept 26 | { 27 | if (p == nullptr) 28 | return; 29 | 30 | internal::Helpers::remove_map_entry (plane_map, plane_map_mutex, p->plane); 31 | } 32 | 33 | NcReel* Plane::ncreel_create (const ncreel_options *popts) 34 | { 35 | return new NcReel (this, popts); 36 | } 37 | -------------------------------------------------------------------------------- /src/libcpp/Plot.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ncpp; 5 | 6 | ncplot_options PlotD::default_options = { 7 | 0, // maxchannels 8 | 0, // minchannels 9 | 0, // legendstyle 10 | ncblitter_e::NCBLIT_1x1, // ncblitter_e 11 | 0, // rangex 12 | "", // title 13 | 0, // flags 14 | }; 15 | 16 | ncplot_options PlotU::default_options = { 17 | 0, // maxchannels 18 | 0, // minchannels 19 | 0, // legendstyle 20 | ncblitter_e::NCBLIT_1x1, // ncblitter_e 21 | 0, // rangex 22 | "", // title 23 | 0, // flags 24 | }; 25 | 26 | Plane* PlotD::get_plane () const noexcept 27 | { 28 | return Plane::map_plane (ncdplot_plane (get_plot ())); 29 | } 30 | 31 | Plane* PlotU::get_plane () const noexcept 32 | { 33 | return Plane::map_plane (ncuplot_plane (get_plot ())); 34 | } 35 | -------------------------------------------------------------------------------- /src/libcpp/Reel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace ncpp; 6 | 7 | ncreel_options NcReel::default_options = { 8 | /* bordermask */ NCBox::MaskBottom | NCBox::MaskTop | NCBox::MaskRight | NCBox::MaskLeft, 9 | /* borderchan */ 0, 10 | /* tabletmask */ 0, 11 | /* tabletchan */ 0, 12 | /* focusedchan */ 0, 13 | /* flags */ 0, 14 | }; 15 | 16 | Plane* NcReel::get_plane () const noexcept 17 | { 18 | return Plane::map_plane (ncreel_plane (reel)); 19 | } 20 | -------------------------------------------------------------------------------- /src/libcpp/Root.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ncpp; 5 | 6 | notcurses* Root::get_notcurses () const 7 | { 8 | notcurses *ret; 9 | 10 | if (nc != nullptr) 11 | ret = *nc; 12 | else 13 | ret = NotCurses::get_instance (); 14 | 15 | if (ret == nullptr) 16 | throw invalid_state_error (ncpp_invalid_state_message); 17 | return ret; 18 | } 19 | 20 | bool Root::is_notcurses_stopped () const noexcept 21 | { 22 | return NotCurses::is_notcurses_stopped (nc); 23 | } 24 | -------------------------------------------------------------------------------- /src/libcpp/Selector.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ncpp; 5 | 6 | ncselector_options Selector::default_options = { 7 | /* title */ nullptr, 8 | /* secondary */ nullptr, 9 | /* footer */ nullptr, 10 | /* items */ nullptr, 11 | /* defidx */ 0, 12 | /* maxdisplay */ 0, 13 | /* opchannels */ 0, 14 | /* descchannels */ 0, 15 | /* titlechannels */ 0, 16 | /* footchannels */ 0, 17 | /* boxchannels */ 0, 18 | /* flags */ 0, 19 | }; 20 | 21 | Plane* Selector::get_plane () const noexcept 22 | { 23 | return Plane::map_plane (ncselector_plane (selector)); 24 | } 25 | -------------------------------------------------------------------------------- /src/libcpp/Subproc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace ncpp; 4 | 5 | ncsubproc_options Subproc::default_options = { 6 | nullptr, // curry 7 | 0, // restart_period 8 | 0, // flags 9 | }; 10 | -------------------------------------------------------------------------------- /src/libcpp/Tablet.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace ncpp; 6 | 7 | std::map *NcTablet::tablet_map = nullptr; 8 | std::mutex NcTablet::tablet_map_mutex; 9 | 10 | NcTablet* NcTablet::map_tablet (nctablet *t, NotCurses *ncinst) noexcept 11 | { 12 | if (t == nullptr) 13 | return nullptr; 14 | 15 | return internal::Helpers::lookup_map_entry ( 16 | tablet_map, 17 | tablet_map_mutex, 18 | t, 19 | [&] (nctablet *_t) -> NcTablet* { 20 | return new NcTablet (_t, ncinst); 21 | } 22 | ); 23 | } 24 | 25 | void NcTablet::unmap_tablet (NcTablet *p) noexcept 26 | { 27 | if (p == nullptr) 28 | return; 29 | 30 | internal::Helpers::remove_map_entry (tablet_map, tablet_map_mutex, p->_tablet); 31 | } 32 | 33 | Plane* NcTablet::get_plane () const noexcept 34 | { 35 | return Plane::map_plane (nctablet_plane (_tablet)); 36 | } 37 | -------------------------------------------------------------------------------- /src/libcpp/Utilities.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace ncpp; 5 | 6 | ncplane* Utilities::to_ncplane (const Plane *plane) noexcept 7 | { 8 | if (plane == nullptr) 9 | return nullptr; 10 | 11 | return const_cast(plane)->to_ncplane (); 12 | } 13 | 14 | NotCurses* Utilities::get_notcurses_cpp (const Root *o) noexcept 15 | { 16 | if (o == nullptr) 17 | return nullptr; 18 | 19 | return const_cast(o)->get_notcurses_cpp (); 20 | } 21 | 22 | NotCurses* Utilities::get_notcurses_cpp (const Plane *plane) noexcept 23 | { 24 | return get_notcurses_cpp (static_cast(plane)); 25 | } 26 | -------------------------------------------------------------------------------- /src/man/parse.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_MAN_PARSE 2 | #define NOTCURSES_MAN_PARSE 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | typedef enum { 12 | LINE_UNKNOWN, 13 | LINE_COMMENT, 14 | LINE_B, LINE_BI, LINE_BR, LINE_I, LINE_IB, LINE_IR, 15 | LINE_RB, LINE_RI, LINE_SB, LINE_SM, 16 | LINE_EE, LINE_EX, LINE_RE, LINE_RS, 17 | LINE_SH, LINE_SS, LINE_TH, 18 | LINE_IP, LINE_LP, LINE_P, LINE_PP, 19 | LINE_TP, LINE_TQ, 20 | LINE_ME, LINE_MT, LINE_UE, LINE_UR, 21 | LINE_OP, LINE_SY, LINE_YS, 22 | LINE_NF, LINE_FI, 23 | } ltypes; 24 | 25 | typedef enum { 26 | TROFF_UNKNOWN, 27 | TROFF_COMMENT, 28 | TROFF_FONT, 29 | TROFF_STRUCTURE, 30 | TROFF_PARAGRAPH, 31 | TROFF_HYPERLINK, 32 | TROFF_SYNOPSIS, 33 | TROFF_PREFORMATTED, 34 | } ttypes; 35 | 36 | typedef struct { 37 | ltypes ltype; 38 | const char* symbol; 39 | ttypes ttype; 40 | uint32_t channel; 41 | } trofftype; 42 | 43 | // the troff trie is only defined on the 128 ascii values. 44 | struct troffnode { 45 | struct troffnode* next[0x80]; 46 | const trofftype *ttype; 47 | }; 48 | 49 | typedef struct pagenode { 50 | char* text; 51 | const trofftype* ttype; 52 | struct pagenode* subs; 53 | unsigned subcount; 54 | } pagenode; 55 | 56 | typedef struct pagedom { 57 | struct pagenode* root; 58 | struct troffnode* trie; 59 | char* title; 60 | char* section; 61 | char* version; 62 | char* footer; 63 | char* header; 64 | struct docstructure* ds; 65 | } pagedom; 66 | 67 | static inline const char* 68 | dom_get_title(const pagedom* dom){ 69 | return dom->title; 70 | } 71 | 72 | const trofftype* 73 | get_type(const struct troffnode* trie, const unsigned char** ws, size_t len); 74 | 75 | struct troffnode* trofftrie(void); 76 | 77 | int troff_parse(const unsigned char* map, size_t mlen, pagedom* dom); 78 | 79 | void destroy_trofftrie(struct troffnode* root); 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/man/structure.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_MAN_STRUCTURE 2 | #define NOTCURSES_MAN_STRUCTURE 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | struct ncplane; 9 | struct docstructure; 10 | 11 | struct docstructure* docstructure_create(struct ncplane* n); 12 | void docstructure_free(struct docstructure* ds); 13 | 14 | void docstructure_toggle(struct ncplane* p, struct ncplane* b, struct docstructure *ds); 15 | 16 | // add the specified [sub]section to the document strucure. 17 | int docstructure_add(struct docstructure* ds, const char* title, int y); 18 | 19 | // update the docstructure browser based off a move of the page plane from to |newy|. 20 | // |movedown| ought be non-zero iff the move was down. 21 | int docstructure_move(struct docstructure* ds, int newy, unsigned movedown); 22 | 23 | int docstructure_prev(struct docstructure* ds); 24 | int docstructure_next(struct docstructure* ds); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/media/none.c: -------------------------------------------------------------------------------- 1 | #include "builddef.h" 2 | #ifndef USE_OIIO 3 | #ifndef USE_FFMPEG 4 | #include "lib/internal.h" 5 | 6 | static void 7 | printbanner(fbuf* f){ 8 | fbuf_puts(f, "built without multimedia support" NL); 9 | } 10 | 11 | ncvisual_implementation local_visual_implementation = { 12 | .visual_printbanner = printbanner, 13 | }; 14 | 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /src/media/oiio.h: -------------------------------------------------------------------------------- 1 | #ifndef MEDIA_OIIO 2 | #define MEDIA_OIIO 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "lib/internal.h" 9 | 10 | int oiio_decode(ncvisual* nc); 11 | struct ncvisual_details* oiio_details_init(void); 12 | void oiio_printbanner(fbuf* f); 13 | void oiio_details_seed(struct ncvisual* ncv); 14 | int oiio_blit(const ncvisual* ncv, unsigned rows, unsigned cols, 15 | struct ncplane* n, const struct blitset* bset, 16 | const blitterargs* bargs); 17 | ncvisual* oiio_from_file(const char* filename); 18 | int oiio_decode_loop(ncvisual* ncv); 19 | int oiio_resize(ncvisual* nc, unsigned rows, unsigned cols); 20 | ncvisual* oiio_create(void); 21 | void oiio_destroy(ncvisual* ncv); 22 | int oiio_blit_dispatch(struct ncplane* nc, const struct blitset* bset, 23 | int linesize, const void* data, 24 | int leny, int lenx, const blitterargs* bargs); 25 | int oiio_init(int logl); 26 | 27 | extern ncvisual_implementation local_visual_implementation; 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/media/shim.c: -------------------------------------------------------------------------------- 1 | #include "notcurses/direct.h" 2 | #include "lib/internal.h" 3 | 4 | extern ncvisual_implementation local_visual_implementation; 5 | 6 | ncdirect* ncdirect_init(const char* termtype, FILE* outfp, uint64_t flags){ 7 | visual_implementation = &local_visual_implementation; 8 | return ncdirect_core_init(termtype, outfp, flags); 9 | } 10 | 11 | notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){ 12 | visual_implementation = &local_visual_implementation; 13 | return notcurses_core_init(opts, outfp); 14 | } 15 | -------------------------------------------------------------------------------- /src/poc/blitters.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "compat/compat.c" 6 | 7 | int main(int argc, char** argv){ 8 | if(setlocale(LC_ALL, "") == NULL){ 9 | fprintf(stderr, "Couldn't set locale based off LANG\n"); 10 | return EXIT_FAILURE; 11 | } 12 | if(argc < 2){ 13 | fprintf(stderr, "usage: blitters file [files...]\n"); 14 | return EXIT_FAILURE; 15 | } 16 | struct notcurses_options nopts = { 17 | .flags = NCOPTION_INHIBIT_SETLOCALE | NCOPTION_NO_ALTERNATE_SCREEN 18 | | NCOPTION_DRAIN_INPUT, 19 | }; 20 | struct notcurses* nc = notcurses_init(&nopts, NULL); 21 | if(nc == NULL){ 22 | return EXIT_FAILURE; 23 | } 24 | struct ncplane* std = notcurses_stdplane(nc); 25 | const int blitters[] = { 26 | NCBLIT_DEFAULT, // let the ncvisual pick 27 | NCBLIT_1x1, // full block 28 | NCBLIT_2x1, // full/(upper|left) blocks 29 | NCBLIT_2x2, // quadrants 30 | NCBLIT_3x2, // sextants 31 | NCBLIT_4x2, // octants 32 | NCBLIT_BRAILLE, // 4 rows, 2 cols (braille) 33 | NCBLIT_PIXEL, // pixel graphics 34 | -1, 35 | }; 36 | for(const int* blitter = blitters ; *blitter >= 0 ; ++blitter){ 37 | for(int scaling = NCSCALE_NONE ; scaling <= NCSCALE_STRETCH ; ++scaling){ 38 | for(int i = 1 ; i < argc ; ++i){ 39 | ncplane_erase(std); 40 | const char* fname = argv[i]; 41 | struct ncvisual* ncv = ncvisual_from_file(fname); 42 | if(ncv == NULL){ 43 | goto err; 44 | } 45 | notcurses_render(nc); 46 | struct ncvisual_options vopts = { 47 | .scaling = scaling, 48 | .blitter = *blitter, 49 | .n = notcurses_stdplane(nc), 50 | .flags = NCVISUAL_OPTION_CHILDPLANE, 51 | }; 52 | struct ncplane* cn; 53 | if((cn = ncvisual_blit(nc, ncv, &vopts)) == NULL){ 54 | ncvisual_destroy(ncv); 55 | goto err; 56 | } 57 | notcurses_render(nc); 58 | struct timespec ts = { 59 | .tv_sec = 0, 60 | .tv_nsec = 500000000, 61 | }; 62 | clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); 63 | ncvisual_destroy(ncv); 64 | ncplane_destroy(cn); 65 | } 66 | } 67 | } 68 | notcurses_stop(nc); 69 | return EXIT_SUCCESS; 70 | 71 | err: 72 | notcurses_stop(nc); 73 | return EXIT_FAILURE; 74 | } 75 | -------------------------------------------------------------------------------- /src/poc/cjkscroll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void){ 6 | setlocale(LC_ALL, ""); 7 | notcurses_options nopts = { 8 | .flags = NCOPTION_INHIBIT_SETLOCALE 9 | | NCOPTION_CLI_MODE 10 | | NCOPTION_DRAIN_INPUT, 11 | }; 12 | struct notcurses* nc = notcurses_core_init(&nopts, NULL); 13 | if(nc == NULL){ 14 | return EXIT_FAILURE; 15 | } 16 | unsigned dimy, dimx; 17 | struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); 18 | wchar_t wc = 0x4e00; 19 | ncplane_set_styles(n, NCSTYLE_BOLD); 20 | ncplane_putstr(n, "This program is *not* indicative of real scrolling speed.\n"); 21 | ncplane_set_styles(n, NCSTYLE_NONE); 22 | unsigned y = ncplane_cursor_y(n); 23 | while(true){ 24 | struct timespec req = { .tv_sec = 0, .tv_nsec = 1000000, }; 25 | nanosleep(&req, NULL); 26 | if(ncplane_putwc(n, wc) <= 0){ 27 | break; 28 | } 29 | if(++wc == 0x9fa5){ 30 | wc = 0x4e00; 31 | } 32 | unsigned newy = ncplane_cursor_y(n); 33 | if(newy != y){ 34 | y = newy; 35 | notcurses_render(nc); 36 | } 37 | } 38 | if(notcurses_render(nc)){ 39 | notcurses_stop(nc); 40 | return EXIT_FAILURE; 41 | } 42 | notcurses_stop(nc); 43 | return EXIT_FAILURE; 44 | } 45 | -------------------------------------------------------------------------------- /src/poc/cli1.c: -------------------------------------------------------------------------------- 1 | #ifndef __MINGW32__ 2 | #include 3 | #endif 4 | #include 5 | 6 | int main(void){ 7 | struct notcurses_options nopts = { 8 | .flags = NCOPTION_CLI_MODE, 9 | }; 10 | struct notcurses* nc = notcurses_init(&nopts, NULL); 11 | if(nc == NULL){ 12 | return EXIT_FAILURE; 13 | } 14 | struct ncplane* stdn = notcurses_stdplane(nc); 15 | ncinput ni; 16 | do{ 17 | if(ncplane_putstr(stdn, "press any key, q to quit\n") < 0){ 18 | goto err; 19 | } 20 | if(notcurses_render(nc)){ 21 | goto err; 22 | } 23 | do{ 24 | // just some pointless testing of notcurses_inputready_fd() here 25 | #ifndef __MINGW32__ 26 | struct pollfd pfd = { 27 | .fd = notcurses_inputready_fd(nc), 28 | .events = POLLIN, 29 | }; 30 | while(poll(&pfd, 1, -1) <= 0){ 31 | } 32 | #endif 33 | notcurses_get_blocking(nc, &ni); 34 | }while(ni.evtype == NCTYPE_RELEASE); 35 | }while(ni.id != 'q' && ni.id != NCKEY_EOF); 36 | if(notcurses_render(nc)){ 37 | goto err; 38 | } 39 | notcurses_stop(nc); 40 | return EXIT_SUCCESS; 41 | 42 | err: 43 | notcurses_stop(nc); 44 | return EXIT_FAILURE; 45 | } 46 | -------------------------------------------------------------------------------- /src/poc/cli2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void){ 4 | struct notcurses_options opts = { 5 | .flags = NCOPTION_CLI_MODE | 6 | NCOPTION_DRAIN_INPUT, 7 | }; 8 | struct notcurses* nc = notcurses_init(&opts, NULL); 9 | if(nc == NULL){ 10 | return EXIT_FAILURE; 11 | } 12 | notcurses_render(nc); 13 | notcurses_stop(nc); 14 | return EXIT_SUCCESS; 15 | } 16 | -------------------------------------------------------------------------------- /src/poc/cli3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void){ 4 | // explicitly want alternate screen, so no NCOPTION_CLI_MODE 5 | struct notcurses_options opts = { 6 | .flags = NCOPTION_PRESERVE_CURSOR | 7 | NCOPTION_NO_CLEAR_BITMAPS | 8 | NCOPTION_DRAIN_INPUT, 9 | }; 10 | struct notcurses* nc = notcurses_init(&opts, NULL); 11 | if(nc == NULL){ 12 | return EXIT_FAILURE; 13 | } 14 | notcurses_render(nc); 15 | notcurses_stop(nc); 16 | return EXIT_SUCCESS; 17 | } 18 | -------------------------------------------------------------------------------- /src/poc/direct-input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void){ 7 | struct ncdirect* n = ncdirect_core_init(NULL, NULL, 0); 8 | if(n == NULL){ 9 | return EXIT_FAILURE; 10 | } 11 | ncinput ni; 12 | uint32_t i; 13 | while((i = ncdirect_get_blocking(n, &ni)) != (uint32_t)-1){ 14 | unsigned char utf8[5] = {0}; 15 | notcurses_ucs32_to_utf8(&i, 1, utf8, sizeof(utf8)); 16 | printf("Read input: [%c%c%c] %s\n", 17 | ncinput_ctrl_p(&ni) ? 'C' : 'c', 18 | ncinput_alt_p(&ni) ? 'A' : 'a', 19 | ncinput_shift_p(&ni) ? 'S' : 's', 20 | utf8); 21 | if(ncinput_ctrl_p(&ni) && i == 'D'){ 22 | break; 23 | } 24 | } 25 | if(ncdirect_stop(n) || i == (uint32_t)-1){ 26 | fprintf(stderr, "Failure reading input (%s)\n", strerror(errno)); 27 | return EXIT_FAILURE; 28 | } 29 | return EXIT_SUCCESS; 30 | } 31 | -------------------------------------------------------------------------------- /src/poc/direct.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // can we leave what was already on the screen there? (narrator: it seems not) 10 | int main(void){ 11 | if(!setlocale(LC_ALL, "")){ 12 | fprintf(stderr, "Couldn't set locale\n"); 13 | return EXIT_FAILURE; 14 | } 15 | struct ncdirect* n; // see bug #391 16 | if((n = ncdirect_core_init(NULL, NULL, 0)) == NULL){ 17 | return EXIT_FAILURE; 18 | } 19 | int dimy = ncdirect_dim_y(n); 20 | int dimx = ncdirect_dim_x(n); 21 | for(int y = 0 ; y < dimy ; ++y){ 22 | for(int x = 0 ; x < dimx ; ++x){ 23 | printf("X"); 24 | } 25 | } 26 | int ret = 0; 27 | ret |= ncdirect_set_fg_rgb(n, 0xff8080); 28 | ret |= ncdirect_on_styles(n, NCSTYLE_BOLD); 29 | printf(" erp erp \n"); 30 | ret |= ncdirect_set_fg_rgb(n, 0x80ff80); 31 | printf(" erp erp \n"); 32 | ret |= ncdirect_off_styles(n, NCSTYLE_BOLD); 33 | printf(" erp erp \n"); 34 | ret |= ncdirect_set_fg_rgb(n, 0xff8080); 35 | printf(" erp erp \n"); 36 | ret |= ncdirect_cursor_right(n, dimx / 2); 37 | ret |= ncdirect_cursor_up(n, dimy / 2); 38 | printf(" erperperp! \n"); 39 | unsigned y, x; 40 | // FIXME try a push/pop 41 | if(ncdirect_cursor_yx(n, &y, &x) == 0){ 42 | printf("\n\tRead cursor position: y: %d x: %d\n", y, x); 43 | y += 2; // we just went down two lines 44 | while(y > 3){ 45 | ret = -1; 46 | unsigned newy; 47 | if(ncdirect_cursor_yx(n, &newy, NULL)){ 48 | break; 49 | } 50 | if(newy != y){ 51 | fprintf(stderr, "Expected %d, got %d\n", y, newy); 52 | break; 53 | } 54 | printf("\n\tRead cursor position: y: %d x: %d\n", newy, x); 55 | y += 2; 56 | const int up = 3; 57 | if(ncdirect_cursor_up(n, up)){ 58 | break; 59 | } 60 | y -= up; 61 | ret = 0; 62 | } 63 | }else{ 64 | ret = -1; 65 | } 66 | return ncdirect_stop(n) || ret ? EXIT_FAILURE : EXIT_SUCCESS; 67 | } 68 | -------------------------------------------------------------------------------- /src/poc/dirlines.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void){ 6 | if(!setlocale(LC_ALL, "")){ 7 | return EXIT_FAILURE; 8 | } 9 | uint64_t flags = NCDIRECT_OPTION_DRAIN_INPUT; 10 | struct ncdirect* n = ncdirect_core_init(NULL, stdout, flags); 11 | for(int i = 1 ; i < 15 ; ++i){ 12 | uint64_t c1 = 0, c2 = 0; 13 | ncchannels_set_fg_rgb8(&c1, 0x0, 0x10 * i, 0xff); 14 | ncchannels_set_fg_rgb8(&c2, 0x10 * i, 0x0, 0x0); 15 | if(ncdirect_hline_interp(n, "-", i, c1, c2) < i){ 16 | ncdirect_stop(n); 17 | return EXIT_FAILURE; 18 | } 19 | ncdirect_set_fg_default(n); 20 | ncdirect_set_bg_default(n); 21 | putchar('\n'); 22 | } 23 | for(int i = 1 ; i < 15 ; ++i){ 24 | uint64_t c1 = 0, c2 = 0; 25 | ncchannels_set_fg_rgb8(&c1, 0x0, 0x10 * i, 0xff); 26 | ncchannels_set_fg_rgb8(&c2, 0x10 * i, 0x0, 0x0); 27 | if(ncdirect_vline_interp(n, "|", i, c1, c2) < i){ 28 | ncdirect_stop(n); 29 | return EXIT_FAILURE; 30 | } 31 | ncdirect_set_fg_default(n); 32 | ncdirect_set_bg_default(n); 33 | if(i < 14){ 34 | if(ncdirect_cursor_up(n, i)){ 35 | ncdirect_stop(n); 36 | return EXIT_FAILURE; 37 | } 38 | } 39 | } 40 | printf("\n"); 41 | uint64_t ul, ur, ll, lr; 42 | ul = ur = ll = lr = 0; 43 | ncchannels_set_fg_rgb8(&ul, 0xff, 0x0, 0xff); 44 | ncchannels_set_fg_rgb8(&ur, 0x0, 0xff, 0x0); 45 | ncchannels_set_fg_rgb8(&ll, 0x0, 0x0, 0xff); 46 | ncchannels_set_fg_rgb8(&lr, 0xff, 0x0, 0x0); 47 | if(ncdirect_rounded_box(n, ul, ur, ll, lr, 10, 10, 0) < 0){ 48 | ncdirect_stop(n); 49 | return EXIT_FAILURE; 50 | } 51 | ncdirect_cursor_up(n, 9); 52 | if(ncdirect_double_box(n, ul, ur, ll, lr, 10, 20, 0) < 0){ 53 | ncdirect_stop(n); 54 | return EXIT_FAILURE; 55 | } 56 | printf("\n"); 57 | if(ncdirect_stop(n)){ 58 | return EXIT_FAILURE; 59 | } 60 | return EXIT_SUCCESS; 61 | } 62 | -------------------------------------------------------------------------------- /src/poc/fbconscroll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char** argv){ 5 | int rows = 1; 6 | if(argc > 2){ 7 | fprintf(stderr, "usage: fbconscroll [rows]\n"); 8 | return EXIT_FAILURE; 9 | }else if(argc == 2){ 10 | rows = atoi(argv[1]); 11 | if(rows < 1){ 12 | fprintf(stderr, "usage: fbconscroll [rows]\n"); 13 | return EXIT_FAILURE; 14 | } 15 | } 16 | struct notcurses_options nopts = { 17 | .flags = NCOPTION_CLI_MODE 18 | | NCOPTION_SUPPRESS_BANNERS 19 | | NCOPTION_NO_FONT_CHANGES 20 | | NCOPTION_DRAIN_INPUT, 21 | }; 22 | struct notcurses* nc = notcurses_init(&nopts, NULL); 23 | if(nc == NULL){ 24 | return EXIT_FAILURE; 25 | } 26 | unsigned dimy, dimx; 27 | struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); 28 | for(int i = 0 ; i < rows ; ++i){ 29 | int r; 30 | if((r = ncplane_putchar(n, '\n')) != 0){ 31 | notcurses_stop(nc); 32 | fprintf(stderr, "RET: %d\n", r); 33 | return EXIT_FAILURE; 34 | } 35 | } 36 | notcurses_render(nc); 37 | notcurses_stop(nc); 38 | return EXIT_SUCCESS; 39 | } 40 | -------------------------------------------------------------------------------- /src/poc/fileroller.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static bool fddone; 11 | static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 12 | static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 13 | 14 | static int 15 | cb(struct ncfdplane* ncfd, const void* data, size_t len, void* curry){ 16 | int ret = -1; 17 | if(ncplane_putnstr(ncfdplane_plane(ncfd), len, data) >= 0){ 18 | if(!notcurses_render(ncplane_notcurses(ncfdplane_plane(ncfd)))){ 19 | ret = 0; 20 | } 21 | } 22 | (void)len; 23 | (void)curry; 24 | return ret; 25 | } 26 | 27 | static int 28 | eofcb(struct ncfdplane* ncfd, int nerrno, void* curry){ 29 | (void)ncfd; 30 | (void)nerrno; 31 | (void)curry; 32 | pthread_mutex_lock(&lock); 33 | fddone = true; 34 | pthread_mutex_unlock(&lock); 35 | pthread_cond_signal(&cond); 36 | return nerrno; 37 | } 38 | 39 | int main(int argc, char** argv){ 40 | if(argc < 2){ 41 | fprintf(stderr, "usage: fileroller file [ files...]\n"); 42 | return EXIT_FAILURE; 43 | } 44 | setlocale(LC_ALL, ""); 45 | notcurses_options opts = { 46 | .flags = NCOPTION_INHIBIT_SETLOCALE 47 | | NCOPTION_SUPPRESS_BANNERS 48 | | NCOPTION_DRAIN_INPUT, 49 | }; 50 | struct notcurses* nc = notcurses_core_init(&opts, NULL); 51 | struct ncplane* n = notcurses_stdplane(nc); 52 | ncplane_set_scrolling(n, true); 53 | while(*++argv){ 54 | int fd = open(*argv, O_RDONLY|O_CLOEXEC); 55 | if(fd < 0){ 56 | fprintf(stderr, "Couldn't open %s (%s)\n", *argv, strerror(errno)); 57 | goto done; 58 | } 59 | ncfdplane_options nopts = {0}; 60 | struct ncfdplane* ncfp = ncfdplane_create(n, &nopts, fd, cb, eofcb); 61 | pthread_mutex_lock(&lock); 62 | while(!fddone){ 63 | pthread_cond_wait(&cond, &lock); 64 | } 65 | fddone = false; 66 | pthread_mutex_unlock(&lock); 67 | if(ncfdplane_destroy(ncfp)){ 68 | notcurses_stop(nc); 69 | return EXIT_FAILURE; 70 | } 71 | ncplane_set_fg_rgb(n, 0x00bcaa); 72 | ncplane_printf_aligned(n, -1, NCALIGN_CENTER, "press any key to continue (%s)", *argv); 73 | notcurses_render(nc); 74 | notcurses_get(nc, NULL, NULL); 75 | } 76 | 77 | done: 78 | if(notcurses_stop(nc)){ 79 | return EXIT_FAILURE; 80 | } 81 | return EXIT_SUCCESS; 82 | } 83 | -------------------------------------------------------------------------------- /src/poc/pixel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static int 6 | handle(struct notcurses* nc, const char *fn){ 7 | struct ncvisual* ncv = ncvisual_from_file(fn); 8 | if(ncv == NULL){ 9 | return -1; 10 | } 11 | unsigned dimy, dimx; 12 | struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx); 13 | for(unsigned y = 0 ; y < dimy ; y += 15){ 14 | for(unsigned x = 0 ; x < dimx ; x += 15){ 15 | uint64_t channels = NCCHANNELS_INITIALIZER(rand() % 256, rand() % 256, 100, rand() % 256, 100, 140); 16 | ncplane_set_base(stdn, "a", 0, channels); 17 | struct ncvisual_options vopts = { 18 | .n = notcurses_stdplane(nc), 19 | .y = y, 20 | .x = x, 21 | .scaling = NCSCALE_NONE_HIRES, 22 | .blitter = NCBLIT_PIXEL, 23 | .flags = NCVISUAL_OPTION_CHILDPLANE | NCVISUAL_OPTION_NODEGRADE, 24 | }; 25 | struct ncplane* nv = ncvisual_blit(nc, ncv, &vopts); 26 | if(nv == NULL){ 27 | ncvisual_destroy(ncv); 28 | return -1; 29 | } 30 | notcurses_render(nc); 31 | sleep(1); 32 | channels = NCCHANNELS_INITIALIZER(rand() % 256, rand() % 256, 100, rand() % 256, 100, 140); 33 | ncplane_set_base(stdn, "a", 0, channels); 34 | notcurses_render(nc); 35 | sleep(1); 36 | ncplane_destroy(nv); 37 | } 38 | } 39 | ncvisual_destroy(ncv); 40 | return 0; 41 | } 42 | 43 | int main(int argc, char** argv){ 44 | if(argc < 2){ 45 | fprintf(stderr, "need image arguments\n"); 46 | return EXIT_FAILURE; 47 | } 48 | char** a = argv + 1; 49 | struct notcurses_options opts = { 50 | .margin_t = 2, 51 | .margin_l = 2, 52 | .margin_b = 2, 53 | .margin_r = 2, 54 | .flags = NCOPTION_DRAIN_INPUT, 55 | }; 56 | struct notcurses* nc = notcurses_init(&opts, NULL); 57 | if(notcurses_check_pixel_support(nc) <= 0){ 58 | notcurses_stop(nc); 59 | fprintf(stderr, "this program requires pixel graphics support\n"); 60 | return EXIT_FAILURE; 61 | } 62 | do{ 63 | handle(nc, *a); 64 | }while(*++a); 65 | notcurses_stop(nc); 66 | return EXIT_SUCCESS; 67 | } 68 | -------------------------------------------------------------------------------- /src/poc/qrcode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static int 6 | render_qrcode(struct ncplane* n, int dimy, int dimx, const char* text){ 7 | unsigned y = dimy, x = dimx; 8 | ncplane_home(n); 9 | int ver = ncplane_qrcode(n, &y, &x, text, strlen(text)); 10 | if(ver < 0){ 11 | return -1; 12 | } 13 | if(ncplane_putstr_yx(n, y + 1, 0, text) < 0){ 14 | return -1; 15 | } 16 | if(notcurses_render(ncplane_notcurses(n))){ 17 | return -1; 18 | } 19 | sleep(2); 20 | return 0; 21 | } 22 | 23 | int main(int argc, const char** argv){ 24 | if(setlocale(LC_ALL, "") == NULL){ 25 | return EXIT_FAILURE; 26 | } 27 | struct notcurses_options opts = { 28 | .flags = NCOPTION_INHIBIT_SETLOCALE 29 | | NCOPTION_NO_ALTERNATE_SCREEN 30 | | NCOPTION_DRAIN_INPUT, 31 | }; 32 | struct notcurses* nc = notcurses_init(&opts, NULL); 33 | unsigned dimy, dimx; 34 | struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx); 35 | while(*++argv){ 36 | if(render_qrcode(std, dimy, dimx, *argv)){ 37 | notcurses_stop(nc); 38 | return EXIT_FAILURE; 39 | } 40 | } 41 | if(argc < 2){ 42 | if(render_qrcode(std, dimy, dimx, "https://nick-black.com")){ 43 | notcurses_stop(nc); 44 | return EXIT_FAILURE; 45 | } 46 | } 47 | notcurses_stop(nc); 48 | return EXIT_SUCCESS; 49 | } 50 | -------------------------------------------------------------------------------- /src/poc/readline.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // play with libreadline as wrapped by notcurses-direct 4 | 5 | static int 6 | rl(struct ncdirect* n){ 7 | char* l; 8 | while( (l = ncdirect_readline(n, "[ncdirect] ")) ){ 9 | fprintf(stderr, "input: [%s]\n", l); 10 | free(l); 11 | } 12 | return 0; 13 | } 14 | 15 | static void 16 | usage(void){ 17 | fprintf(stderr, "usage: readline [ -v ]\n"); 18 | exit(EXIT_FAILURE); 19 | } 20 | 21 | int main(int argc, char** argv){ 22 | uint64_t flags = 0; 23 | if(argc != 1){ 24 | if(argc != 2){ 25 | usage(); 26 | } 27 | if(strcmp(argv[1], "-v")){ 28 | usage(); 29 | } 30 | flags = NCDIRECT_OPTION_VERY_VERBOSE; 31 | } 32 | struct ncdirect* n = ncdirect_core_init(NULL, NULL, flags); 33 | if(n == NULL){ 34 | return EXIT_FAILURE; 35 | } 36 | rl(n); 37 | if(ncdirect_stop(n)){ 38 | return EXIT_FAILURE; 39 | } 40 | return EXIT_SUCCESS; 41 | } 42 | -------------------------------------------------------------------------------- /src/poc/rgb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void){ 7 | if(!setlocale(LC_ALL, "")){ 8 | fprintf(stderr, "Couldn't set locale\n"); 9 | return EXIT_FAILURE; 10 | } 11 | struct notcurses_options opts = { 12 | .flags = NCOPTION_INHIBIT_SETLOCALE 13 | | NCOPTION_NO_ALTERNATE_SCREEN 14 | | NCOPTION_DRAIN_INPUT, 15 | }; 16 | struct notcurses* nc = notcurses_core_init(&opts, NULL); 17 | if(nc == NULL){ 18 | return EXIT_FAILURE; 19 | } 20 | unsigned dimy, dimx; 21 | struct ncplane* n = notcurses_stdplane(nc); 22 | ncplane_dim_yx(n, &dimy, &dimx); 23 | int r , g, b; 24 | r = 0; 25 | g = 0x80; 26 | b = 0; 27 | ncplane_set_bg_rgb8(n, 0x40, 0x20, 0x40); 28 | for(unsigned y = 0 ; y < dimy ; ++y){ 29 | for(unsigned x = 0 ; x < dimx ; ++x){ 30 | if(ncplane_set_fg_rgb8(n, r, g, b)){ 31 | goto err; 32 | } 33 | if(ncplane_cursor_move_yx(n, y, x)){ 34 | goto err; 35 | } 36 | if(ncplane_putchar(n, 'x') <= 0){ 37 | goto err; 38 | } 39 | if(g % 2){ 40 | if(--b <= 0){ 41 | ++g; 42 | b = 0; 43 | } 44 | }else{ 45 | if(++b >= 256){ 46 | ++g; 47 | b = 255; 48 | } 49 | } 50 | } 51 | } 52 | if(notcurses_render(nc)){ 53 | notcurses_stop(nc); 54 | return EXIT_FAILURE; 55 | } 56 | notcurses_stop(nc); 57 | return EXIT_SUCCESS; 58 | 59 | err: 60 | notcurses_stop(nc); 61 | return EXIT_FAILURE; 62 | } 63 | -------------------------------------------------------------------------------- /src/poc/rtl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void){ 5 | struct notcurses_options opts = { 6 | .flags = NCOPTION_NO_ALTERNATE_SCREEN 7 | | NCOPTION_DRAIN_INPUT, 8 | }; 9 | struct notcurses* nc = notcurses_core_init(&opts, NULL); 10 | if(!nc){ 11 | return EXIT_FAILURE; 12 | } 13 | unsigned dimy, dimx; 14 | struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); 15 | ncplane_printf_yx(n, dimy / 2 - 2, 0, "ࡢ‎ࡣ‎ࡤ‎ࡥ‎ࡦ‎ࡧ‎ࡨ‎ࡩ‎ࡪ‎ࢠ‎ࢡ‎ࢢ‎ࢣ‎ࢤ‎ࢥ‎ࢦ‎ࢧ‎ࢨ‎ࢩ‎ࢪ‎ࢫ‎ࢬ‎ࢭ‎ࢮ‎ࢯ‎ࢰ‎ࢱ‎ࢲ‎ࢳ‎ࢴ‎ࢶ‎ࢷ‎ࢸ‎ࢹ‎ࢺ‎ࢻ‎ࢼ‎ࢽ‎࣢ः"); 16 | ncplane_printf_yx(n, dimy / 2 - 1, 0, "࠲‎࠳‎࠴‎࠵‎࠶‎࠷‎࠸‎࠹‎࠺‎࠻‎࠼‎࠽‎࠾‎ࡀ‎ࡁ‎ࡂ‎ࡃ‎ࡄ‎ࡅ‎ࡆ‎ࡇ‎ࡈ‎ࡉ‎ࡊ‎ࡋ‎ࡌ‎ࡍ‎ࡎ‎ࡏ‎ࡐ‎ࡑ‎ࡒ‎ࡓ‎ࡔ‎ࡕ‎ࡖ‎ࡗ‎ࡘ‎࡞‎ࡡ"); 17 | // no matter how the following string is displayed, the first hebrew 18 | // character is מ (mem), followed by י (yod), ל (lamed), etc. 19 | if(ncplane_printf_aligned(n, dimy / 2, NCALIGN_CENTER, 20 | "I can write English with מילים בעברית in the same sentence.") < 0){ 21 | notcurses_stop(nc); 22 | return EXIT_FAILURE; 23 | } 24 | if(ncplane_printf_aligned(n, dimy / 2 + 1, NCALIGN_CENTER, 25 | "I can write English withמיליםבעבריתin the same sentence.") < 0){ 26 | notcurses_stop(nc); 27 | return EXIT_FAILURE; 28 | } 29 | const char* brew = "םבעברஸீரோகிரிﻧﺎﻠﻘﺻﺮﻴﻧﻖﺻﺭﺎoshitﻠﺷﻮﻗﺎﻠﺴﻛﺮﻳﺓ"; 30 | const char *b = brew; 31 | for(unsigned y = dimy / 2 + 2 ; y < dimy ; ++y){ 32 | for(unsigned x = 0 ; x < dimx ; ++x){ 33 | size_t bytes; 34 | if(ncplane_putegc_yx(n, y, x, b, &bytes) <= 0){ 35 | break; 36 | } 37 | b += bytes; 38 | if(!*b){ 39 | b = brew; 40 | } 41 | } 42 | } 43 | struct ncplane_options nopts = { 44 | .y = dimy / 2 + 3, 45 | .x = 8, 46 | .rows = dimy - (dimy / 2 + 5), 47 | .cols = dimx - 8 * 2, 48 | }; 49 | struct ncplane* top = ncplane_create(n, &nopts); 50 | ncplane_set_base(top, " ", 0, 0); 51 | if(notcurses_render(nc)){ 52 | notcurses_stop(nc); 53 | return EXIT_FAILURE; 54 | } 55 | notcurses_stop(nc); 56 | return EXIT_SUCCESS; 57 | } 58 | -------------------------------------------------------------------------------- /src/poc/scroll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void){ 6 | setlocale(LC_ALL, ""); 7 | struct notcurses_options opts = { 8 | .flags = NCOPTION_INHIBIT_SETLOCALE 9 | | NCOPTION_CLI_MODE 10 | | NCOPTION_DRAIN_INPUT, 11 | }; 12 | struct notcurses* nc = notcurses_core_init(&opts, NULL); 13 | if(nc == NULL){ 14 | return EXIT_FAILURE; 15 | } 16 | unsigned dimy, dimx; 17 | struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); 18 | char c = 'A'; 19 | ncplane_set_styles(n, NCSTYLE_BOLD); 20 | ncplane_putstr(n, "This program is *not* indicative of real scrolling speed.\n"); 21 | ncplane_set_styles(n, NCSTYLE_NONE); 22 | unsigned y = ncplane_cursor_y(n); 23 | while(true){ 24 | struct timespec req = { .tv_sec = 0, .tv_nsec = 1000000, }; 25 | nanosleep(&req, NULL); 26 | if(ncplane_putchar(n, c) != 1){ 27 | break; 28 | } 29 | if(++c == '{'){ 30 | c = 'A'; 31 | } 32 | unsigned newy = ncplane_cursor_y(n); 33 | if(newy != y){ 34 | y = newy; 35 | notcurses_render(nc); 36 | } 37 | } 38 | if(notcurses_render(nc)){ 39 | notcurses_stop(nc); 40 | return EXIT_FAILURE; 41 | } 42 | notcurses_stop(nc); 43 | return EXIT_SUCCESS; 44 | } 45 | -------------------------------------------------------------------------------- /src/poc/sgr-direct.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(void){ 8 | if(!setlocale(LC_ALL, "")){ 9 | return EXIT_FAILURE; 10 | } 11 | struct ncdirect* nc = ncdirect_core_init(NULL, stdout, 0); 12 | if(!nc){ 13 | return EXIT_FAILURE; 14 | } 15 | int e = 0; 16 | for(unsigned i = 0 ; i < (NCSTYLE_ITALIC << 1u) ; ++i){ 17 | if((ncdirect_supported_styles(nc) & i) == i){ 18 | if(ncdirect_set_styles(nc, i)){ 19 | ncdirect_stop(nc); 20 | return EXIT_FAILURE; 21 | } 22 | } 23 | printf("%08x ", i); 24 | if(ncdirect_set_styles(nc, NCSTYLE_NONE)){ 25 | ncdirect_stop(nc); 26 | return EXIT_FAILURE; 27 | } 28 | if(++e % 8 == 0){ 29 | printf("\n"); 30 | } 31 | } 32 | if(e % 8){ 33 | printf("\n"); 34 | } 35 | ncdirect_stop(nc); 36 | return EXIT_SUCCESS; 37 | } 38 | -------------------------------------------------------------------------------- /src/pocpp/ncpp_build.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // This is a **build** test - it does nothing else except ensure that all the C++ wrapper classes are included and that 3 | // the program builds. 4 | // 5 | // Once there are demos which exercise all the C++ classes this "test" can be removed 6 | // 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace ncpp; 25 | 26 | int run () 27 | { 28 | NotCurses nc; 29 | 30 | const char *ncver = nc.version (); 31 | { 32 | Plane p1 (1, 1, 0, 0); 33 | Plot plot1 (p1); 34 | Plane p2 (1, 1, 0, 0); 35 | PlotU plot2 (p2); 36 | Plane p3 (1, 1, 0, 0); 37 | PlotD plot3 (p3); 38 | } 39 | 40 | nc.stop (); 41 | 42 | Direct direct{}; 43 | direct.set_fg_rgb (0xb5, 0x0d, 0xff); 44 | std::cout << "notcurses version: "; 45 | direct.set_bg_rgb (0x05, 0x6e, 0xee); 46 | direct.set_fg_rgb (0xe2, 0xbf, 0x00); 47 | std::cout << ncver << std::endl; 48 | 49 | return 0; 50 | } 51 | 52 | int main () 53 | { 54 | if (!setlocale (LC_ALL, "")){ 55 | std::cerr << "Couldn't set locale based on user preferences" << std::endl; 56 | return EXIT_FAILURE; 57 | } 58 | 59 | try { 60 | return run (); 61 | } catch (ncpp::init_error &e) { 62 | std::cerr << "Initialization error: " << e.what () << std::endl; 63 | } catch (ncpp::invalid_state_error &e) { 64 | std::cerr << "Invalid state error: " << e.what () << std::endl; 65 | } catch (ncpp::invalid_argument &e) { 66 | std::cerr << "Invalid argument error: " << e.what () << std::endl; 67 | } 68 | 69 | return 1; 70 | } 71 | -------------------------------------------------------------------------------- /src/pocpp/ncpp_build_exceptions.cpp: -------------------------------------------------------------------------------- 1 | #define NCPP_EXCEPTIONS_PLEASE 2 | // 3 | // This is a **build** test - it does nothing else except ensure that all the C++ wrapper classes are included and that 4 | // the program builds. 5 | // 6 | // Once there are demos which exercise all the C++ classes this "test" can be removed 7 | // 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace ncpp; 26 | 27 | int run () 28 | { 29 | NotCurses nc; 30 | 31 | const char *ncver = nc.version (); 32 | { 33 | Plane p1 (1, 1, 0, 0); 34 | Plot plot1 (p1); 35 | Plane p2 (1, 1, 0, 0); 36 | PlotU plot2 (p2); 37 | Plane p3 (1, 1, 0, 0); 38 | PlotD plot3 (p3); 39 | } 40 | 41 | nc.stop (); 42 | 43 | Direct direct{}; 44 | direct.set_fg_rgb (0xb5, 0x0d, 0xff); 45 | std::cout << "notcurses version: "; 46 | direct.set_bg_rgb (0x05, 0x6e, 0xee); 47 | direct.set_fg_rgb (0xe2, 0xbf, 0x00); 48 | std::cout << ncver << std::endl; 49 | 50 | return 0; 51 | } 52 | 53 | int main () 54 | { 55 | if (!setlocale (LC_ALL, "")){ 56 | std::cerr << "Couldn't set locale based on user preferences" << std::endl; 57 | return EXIT_FAILURE; 58 | } 59 | 60 | try { 61 | return run (); 62 | } catch (ncpp::init_error &e) { 63 | std::cerr << "Initialization error: " << e.what () << std::endl; 64 | } catch (ncpp::invalid_state_error &e) { 65 | std::cerr << "Invalid state error: " << e.what () << std::endl; 66 | } catch (ncpp::invalid_argument &e) { 67 | std::cerr << "Invalid argument error: " << e.what () << std::endl; 68 | } 69 | 70 | return 1; 71 | } 72 | -------------------------------------------------------------------------------- /src/pocpp/resize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char** argv){ 10 | const char* file = "../data/changes.jpg"; 11 | setlocale(LC_ALL, ""); 12 | if(argc > 2){ 13 | fprintf(stderr, "usage: visual [ file ]\n"); 14 | return EXIT_FAILURE; 15 | }else if(argc == 2){ 16 | file = argv[1]; 17 | } 18 | notcurses_options opts{}; 19 | opts.flags = NCOPTION_INHIBIT_SETLOCALE 20 | | NCOPTION_NO_ALTERNATE_SCREEN 21 | | NCOPTION_DRAIN_INPUT; 22 | struct notcurses* nc; 23 | if((nc = notcurses_init(&opts, nullptr)) == nullptr){ 24 | return EXIT_FAILURE; 25 | } 26 | struct ncvisual_options vopts{}; 27 | bool failed = false; 28 | unsigned dimy, dimx; 29 | int top = 0; 30 | int bot; 31 | auto ncv = ncvisual_from_file(file); 32 | if(!ncv){ 33 | goto err; 34 | } 35 | vopts.n = notcurses_stdplane(nc); 36 | vopts.scaling = NCSCALE_STRETCH; 37 | vopts.flags = NCVISUAL_OPTION_CHILDPLANE; 38 | struct ncplane* ntarg; 39 | if((ntarg = ncvisual_blit(nc, ncv, &vopts)) == nullptr){ 40 | goto err; 41 | } 42 | if(notcurses_render(nc)){ 43 | goto err; 44 | } 45 | ncplane_dim_yx(ntarg, &dimy, &dimx); 46 | // start chopping off rows 47 | bot = dimy - 1; 48 | while(top <= bot){ 49 | // one from top 50 | sleep(1); 51 | if(ncplane_resize(ntarg, 1, 0, bot - top, dimx, 0, 0, bot - top, dimx)){ 52 | goto err; 53 | } 54 | ++top; 55 | if(notcurses_render(nc)){ 56 | goto err; 57 | } 58 | if(top >= bot){ 59 | break; 60 | } 61 | // one from bottom 62 | if(ncplane_resize(ntarg, 0, 0, bot - top, dimx, 0, 0, bot - top, dimx)){ 63 | goto err; 64 | } 65 | --bot; 66 | if(notcurses_render(nc)){ 67 | goto err; 68 | } 69 | } 70 | return notcurses_stop(nc) || failed ? EXIT_FAILURE : EXIT_SUCCESS; 71 | 72 | err: 73 | notcurses_stop(nc); 74 | return EXIT_FAILURE; 75 | } 76 | -------------------------------------------------------------------------------- /src/pocpp/rgbbg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | auto main() -> int { 7 | if(!setlocale(LC_ALL, "")){ 8 | fprintf(stderr, "Couldn't set locale\n"); 9 | return EXIT_FAILURE; 10 | } 11 | notcurses_options opts{}; 12 | opts.flags = NCOPTION_INHIBIT_SETLOCALE 13 | | NCOPTION_NO_ALTERNATE_SCREEN 14 | | NCOPTION_DRAIN_INPUT; 15 | struct notcurses* nc = notcurses_init(&opts, nullptr); 16 | if(nc == nullptr){ 17 | return EXIT_FAILURE; 18 | } 19 | unsigned dimy, dimx; 20 | struct ncplane* n = notcurses_stdplane(nc); 21 | ncplane_dim_yx(n, &dimy, &dimx); 22 | int r , g, b; 23 | r = 0; 24 | g = 0x80; 25 | b = 0; 26 | ncplane_set_fg_rgb8(n, 0x40, 0x20, 0x40); 27 | for(unsigned y = 0 ; y < dimy ; ++y){ 28 | if(ncplane_cursor_move_yx(n, y, 0)){ 29 | goto err; 30 | } 31 | for(unsigned x = 0 ; x < dimx ; ++x){ 32 | if(ncplane_set_bg_rgb8(n, r, g, b)){ 33 | goto err; 34 | } 35 | if(ncplane_putchar(n, 'x') <= 0){ 36 | goto err; 37 | } 38 | if(g % 2){ 39 | if(--b <= 0){ 40 | ++g; 41 | b = 0; 42 | } 43 | }else{ 44 | if(++b >= 256){ 45 | ++g; 46 | b = 255; 47 | } 48 | } 49 | } 50 | } 51 | if(notcurses_render(nc)){ 52 | notcurses_stop(nc); 53 | return EXIT_FAILURE; 54 | } 55 | notcurses_stop(nc); 56 | return EXIT_SUCCESS; 57 | 58 | err: 59 | notcurses_stop(nc); 60 | return EXIT_FAILURE; 61 | } 62 | -------------------------------------------------------------------------------- /src/pocpp/widestomp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace ncpp; 9 | 10 | constexpr auto DELAY = 1; 11 | 12 | // dump two wide glyphs, then create a new plane and drop it atop them 13 | 14 | auto stomper(NotCurses& nc, std::shared_ptr& nn) -> int { 15 | // should knock out both wide glyphs 16 | nn->move(0, 1); 17 | nc.render(); 18 | sleep(DELAY); 19 | 20 | // first wide glyph gone, second present 21 | nn->move(1, 0); 22 | nc.render(); 23 | sleep(DELAY); 24 | 25 | // second wide glyph gone, first present 26 | nn->move(2, 2); 27 | nc.render(); 28 | sleep(DELAY); 29 | 30 | nn->move(4, 0); 31 | nc.render(); 32 | sleep(DELAY); 33 | 34 | nn->move(5, 1); 35 | nc.render(); 36 | sleep(DELAY); 37 | 38 | nn->move(6, 2); 39 | nc.render(); 40 | sleep(DELAY); 41 | 42 | return 0; 43 | } 44 | 45 | auto main() -> int { 46 | setlocale(LC_ALL, ""); 47 | notcurses_options nopts{}; 48 | nopts.flags = NCOPTION_INHIBIT_SETLOCALE 49 | | NCOPTION_DRAIN_INPUT; 50 | NotCurses nc(nopts); 51 | std::shared_ptr n(nc.get_stdplane()); 52 | 53 | { 54 | // first, a 2x1 with "AB" 55 | auto nn = std::make_shared(1, 2, 1, 16); 56 | nn->set_fg_rgb8(0xc0, 0x80, 0xc0); 57 | nn->set_bg_rgb8(0x20, 0x00, 0x20); 58 | nn->set_base("", 0, NCCHANNELS_INITIALIZER(0xc0, 0x80, 0xc0, 0x20, 0, 0x20)); 59 | nn->putstr("AB"); 60 | 61 | n->set_fg_rgb8(0x80, 0xc0, 0x80); 62 | n->set_bg_rgb8(0x00, 0x40, 0x00); 63 | n->putstr("\xe5\xbd\xa2\xe5\x85\xa8"); 64 | n->putstr(1, 0, "\xe5\xbd\xa2\xe5\x85\xa8"); 65 | n->putstr(2, 0, "\xe5\xbd\xa2\xe5\x85\xa8"); 66 | n->putstr(3, 0, "\xe5\xbd\xa2\xe5\x85\xa8"); 67 | n->putstr(4, 0, "abcdef"); 68 | n->putstr(5, 0, "abcdef"); 69 | n->putstr(6, 0, "abcdef"); 70 | n->putstr(7, 0, "abcdef"); 71 | nc.render(); 72 | sleep(1); 73 | 74 | stomper(nc, nn); 75 | if(nn->putstr(0, 0, "\xe5\xbd\xa1") <= 0){ 76 | return EXIT_FAILURE; 77 | } 78 | stomper(nc, nn); 79 | nn->erase(); 80 | if(nn->putstr(0, 0, "r") <= 0){ 81 | return EXIT_FAILURE; 82 | } 83 | stomper(nc, nn); 84 | } 85 | 86 | // now a 1x1 "*" 87 | auto nn = std::make_shared(1, 1, 1, 16); 88 | if(nn->putstr(0, 0, "r") <= 0){ 89 | return EXIT_FAILURE; 90 | } 91 | stomper(nc, nn); 92 | return EXIT_SUCCESS; 93 | } 94 | -------------------------------------------------------------------------------- /src/tests/Exceptions.cpp: -------------------------------------------------------------------------------- 1 | #define NCPP_EXCEPTIONS_PLEASE 2 | #include "main.h" 3 | #include 4 | 5 | using namespace ncpp; 6 | 7 | TEST_CASE("Exceptions") { 8 | 9 | notcurses_options nopts{}; 10 | nopts.flags = NCOPTION_SUPPRESS_BANNERS | 11 | NCOPTION_INHIBIT_SETLOCALE; 12 | nopts.loglevel = NCLOGLEVEL_VERBOSE; 13 | 14 | SUBCASE("GetInstance") { 15 | CHECK_THROWS_AS(NotCurses::get_instance(), invalid_state_error); 16 | } 17 | 18 | SUBCASE("ResetStats") { 19 | NotCurses nc{ nopts }; 20 | CHECK_THROWS_AS(nc.reset_stats(nullptr), invalid_argument); 21 | nc.stop(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/tests/autogrow.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | TEST_CASE("Autogrow") { 4 | auto nc_ = testing_notcurses(); 5 | if(!nc_){ 6 | return; 7 | } 8 | struct ncplane* n_ = notcurses_stdplane(nc_); 9 | REQUIRE(n_); 10 | 11 | // verify that the standard plane has scrolling disabled initially, and that 12 | // we cannot enable it at runtime. 13 | SUBCASE("AutogrowDisabledStdplane") { 14 | CHECK(!ncplane_set_autogrow(n_, true)); // disabled at start? 15 | CHECK(!ncplane_set_autogrow(n_, false)); // attempt to enable failed? 16 | } 17 | 18 | // by default, a new plane ought not have autogrow enabled--but we ought be 19 | // able to enable(+disable) it, unlike the standard plane. 20 | SUBCASE("AutogrowDisabledNewPlane") { 21 | struct ncplane_options nopts{}; 22 | nopts.rows = 10; 23 | nopts.cols = 10; 24 | auto np = ncplane_create(n_, &nopts); 25 | REQUIRE(np); 26 | CHECK(!ncplane_set_autogrow(np, true)); // ought be false by default 27 | CHECK(ncplane_set_autogrow(np, false)); // did we set it true? 28 | CHECK(!ncplane_set_autogrow(np, false)); // did we set it false? 29 | CHECK(0 == notcurses_render(nc_)); 30 | CHECK(0 == ncplane_destroy(np)); 31 | } 32 | 33 | // with the NCPLANE_OPTION_AUTOGROW flag, the plane ought have autogrow 34 | // enabled upon creation. we ought be able to disable it. 35 | SUBCASE("AutogrowDisabledNewPlane") { 36 | struct ncplane_options nopts{}; 37 | nopts.rows = 10; 38 | nopts.cols = 10; 39 | nopts.flags = NCPLANE_OPTION_AUTOGROW; 40 | auto np = ncplane_create(n_, &nopts); 41 | REQUIRE(np); 42 | CHECK(ncplane_set_autogrow(np, false)); // ought be true at creation 43 | CHECK(!ncplane_set_autogrow(np, true)); // did we set it false? 44 | CHECK(ncplane_set_autogrow(np, false)); // did we set it true? 45 | CHECK(0 == notcurses_render(nc_)); 46 | CHECK(0 == ncplane_destroy(np)); 47 | } 48 | 49 | CHECK(0 == notcurses_stop(nc_)); 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/tests/fbuf.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "lib/fbuf.h" 3 | 4 | TEST_CASE("Fbuf") { 5 | auto nc_ = testing_notcurses(); 6 | if(!nc_){ 7 | return; 8 | } 9 | unsigned dimy, dimx; 10 | struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx); 11 | REQUIRE(n_); 12 | REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); 13 | 14 | // check that upon successful initialization, we have some space 15 | SUBCASE("FbufInit") { 16 | fbuf f{}; 17 | CHECK(0 == fbuf_init(&f)); 18 | CHECK(0 < f.size); 19 | CHECK(0 == f.used); 20 | CHECK(nullptr != f.buf); 21 | fbuf_free(&f); 22 | } 23 | 24 | // fill the fbuf a character at a time 25 | SUBCASE("FbufPutcCover") { 26 | fbuf f{}; 27 | CHECK(0 == fbuf_init(&f)); 28 | CHECK(0 < f.size); 29 | CHECK(0 == f.used); 30 | CHECK(nullptr != f.buf); 31 | auto oldsize = f.size; 32 | for(size_t s = 0 ; s < oldsize ; ++s){ 33 | CHECK(1 == fbuf_putc(&f, 'X')); 34 | } 35 | CHECK(f.used == oldsize); 36 | CHECK(oldsize <= f.size); 37 | fbuf_free(&f); 38 | } 39 | 40 | // fill the fbuf with one large write 41 | SUBCASE("FbufPutsCoverSingle") { 42 | fbuf f{}; 43 | CHECK(0 == fbuf_init(&f)); 44 | CHECK(0 < f.size); 45 | CHECK(0 == f.used); 46 | CHECK(nullptr != f.buf); 47 | auto oldsize = f.size; 48 | auto erp = new char[oldsize + 1]; 49 | memset(erp, 'X', oldsize); 50 | erp[oldsize] = '\0'; 51 | CHECK(oldsize == fbuf_puts(&f, erp)); 52 | delete[] erp; 53 | CHECK(f.used == oldsize); 54 | CHECK(oldsize <= f.size); 55 | fbuf_free(&f); 56 | } 57 | 58 | // fill the fbuf with random writes 59 | SUBCASE("FbufPutsCoverRandom") { 60 | fbuf f{}; 61 | CHECK(0 == fbuf_init(&f)); 62 | CHECK(0 < f.size); 63 | CHECK(0 == f.used); 64 | CHECK(nullptr != f.buf); 65 | auto oldsize = f.size; 66 | auto erp = new char[oldsize + 1]; 67 | size_t used = 0; 68 | while(used < oldsize){ 69 | size_t oldused = f.used; 70 | size_t towrite = rand() % (oldsize - used) + 1; 71 | memset(erp, rand() % 26 + 'A', towrite); 72 | erp[towrite] = '\0'; 73 | CHECK(towrite == fbuf_puts(&f, erp)); 74 | CHECK(f.used == oldused + towrite); 75 | used += towrite; 76 | } 77 | delete[] erp; 78 | CHECK(f.used == oldsize); 79 | CHECK(oldsize <= f.size); 80 | fbuf_free(&f); 81 | } 82 | 83 | CHECK(0 == notcurses_stop(nc_)); 84 | } 85 | -------------------------------------------------------------------------------- /src/tests/internal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "main.h" 5 | 6 | TEST_CASE("Internals") { 7 | 8 | SUBCASE("RGBtoANSIWhiteGreyBlack") { 9 | unsigned r; 10 | for(r = 0 ; r < 256 ; ++r){ 11 | int g = rgb_quantize_256(r, r, r); 12 | if(r < 8){ 13 | CHECK(0 == g); 14 | }else if(r > 238){ 15 | CHECK(15 == g); 16 | }else{ 17 | CHECK(g == (r - 8) / 10 + 232); 18 | } 19 | } 20 | } 21 | 22 | // Pure reds are either 0 (black), or 16 plus 36 * [0..5]. 23 | SUBCASE("RGBtoANSIRed") { 24 | unsigned r, g, b; 25 | g = b = 0x0; 26 | for(r = 0 ; r < 256 ; ++r){ 27 | int c256 = rgb_quantize_256(r, g, b); 28 | if(r < 8){ 29 | CHECK(0 == c256); 30 | }else{ 31 | CHECK(15 < c256); 32 | CHECK(16 == c256 % 36); 33 | } 34 | } 35 | } 36 | 37 | // Pure greens are either 0 (black), or 16 plus 6 * [0..5]. 38 | SUBCASE("RGBtoANSIGreen") { 39 | unsigned r, g, b; 40 | r = b = 0x0; 41 | for(g = 0 ; g < 256 ; ++g){ 42 | int c256 = rgb_quantize_256(r, g, b); 43 | CHECK(48 > c256); 44 | if(g < 8){ 45 | CHECK(0 == c256); 46 | }else{ 47 | CHECK(15 < c256); 48 | CHECK(4 == c256 % 6); 49 | } 50 | } 51 | } 52 | 53 | // Pure blues are either 0 (black), or one of the first 6 colors [16..22]. 54 | SUBCASE("RGBtoANSIBlue") { 55 | unsigned r, g, b; 56 | r = g = 0x0; 57 | for(b = 0 ; b < 256 ; ++b){ 58 | int c256 = rgb_quantize_256(r, g, b); 59 | CHECK(22 > c256); 60 | if(b < 8){ 61 | CHECK(0 == c256); 62 | }else{ 63 | CHECK(15 < c256); 64 | } 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/tests/libunistring.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | // some simple tests to ensure the libunistring we've compiled/linked against 4 | // behaves as expected. 5 | 6 | TEST_CASE("Libunistring") { 7 | auto nc_ = testing_notcurses(); 8 | if(!nc_){ 9 | return; 10 | } 11 | ncplane* ncp_ = notcurses_stdplane(nc_); 12 | REQUIRE(ncp_); 13 | 14 | SUBCASE("WordbreakChars") { 15 | const wchar_t breakers[] = { 16 | // L'\u0009', // horizontal tab 17 | L'\u0020', // space 18 | // L'\u007c', // vertical line 19 | // L'\u00ad', // soft hyphen 20 | // L'\u058a', // armenian hyphen 21 | // L'\u0f0b', // tibetan mark intersyllabic tsheg 22 | // L'\u1361', // ethiopic wordspace 23 | L'\u1680', // ogham space mark 24 | //L'\u17d5', // khmer sign bariyoosan 25 | L'\u2000', // en quad 26 | L'\u2001', // em quad 27 | L'\u2002', // en quad 28 | L'\u2003', // em quad 29 | L'\u2004', // three-per-em space 30 | L'\u2005', // four-per-em space 31 | L'\u2006', // six-per-em space 32 | L'\u2008', // punctuation space 33 | L'\u2009', // thin space 34 | L'\u200a', // hair space 35 | //L'\u2010', // hyphen 36 | //L'\u2027', // hyphenation point 37 | 0 38 | }, *b; 39 | for(b = breakers ; *b ; ++b){ 40 | if(!iswordbreak(*b)){ 41 | fprintf(stderr, "Unexpectedly fails to wordbreak: U+%04x [%lc]\n", *b, *b); 42 | } 43 | CHECK(iswordbreak(*b)); 44 | } 45 | CHECK(!islinebreak(L'\u000d')); 46 | } 47 | 48 | // \u000d carriage return is *not* a linebreaker 49 | SUBCASE("LinebreakChars") { 50 | const wchar_t breakers[] = { 51 | L'\u000a', // linefeed 52 | L'\u000b', // vertical tab 53 | L'\u000c', // formfeed 54 | 0 55 | }, *b; 56 | for(b = breakers ; *b ; ++b){ 57 | if(!islinebreak(*b)){ 58 | fprintf(stderr, "Unexpectedly fails to linebreak: U+%04x [%lc]\n", *b, *b); 59 | } 60 | CHECK(islinebreak(*b)); 61 | } 62 | CHECK(!islinebreak(L'\u000d')); 63 | } 64 | 65 | CHECK(0 == notcurses_stop(nc_)); 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/tests/main.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTCURSES_TEST_MAIN 2 | #define NOTCURSES_TEST_MAIN 3 | 4 | #include 5 | #include 6 | #include "version.h" 7 | #include "builddef.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "lib/internal.h" 14 | 15 | struct free_deleter{ 16 | template 17 | void operator()(T *p) const { 18 | std::free(const_cast*>(p)); 19 | } 20 | }; 21 | 22 | auto is_test_tty() -> bool; 23 | auto find_data(const char* datum) -> std::unique_ptr; 24 | auto testing_notcurses() -> struct notcurses*; 25 | auto ncreel_validate(const ncreel* n) -> bool; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/tests/multiselector.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include 3 | #include 4 | 5 | TEST_CASE("Multiselectors") { 6 | auto nc_ = testing_notcurses(); 7 | if(!nc_){ 8 | return; 9 | } 10 | struct ncplane* n_ = notcurses_stdplane(nc_); 11 | REQUIRE(n_); 12 | REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); 13 | 14 | // multiselector can't be bound to the standard plane 15 | SUBCASE("RefuseStandardPlane") { 16 | ncmultiselector_options s{}; 17 | struct ncmultiselector* ns = ncmultiselector_create(n_, &s); 18 | REQUIRE(nullptr == ns); 19 | } 20 | 21 | // create a multiselector, but don't explicitly destroy it, thus testing the 22 | // context shutdown cleanup path 23 | SUBCASE("ImplicitDestroy") { 24 | ncmultiselector_options s{}; 25 | struct ncplane_options nopts{}; 26 | nopts.rows = 1; 27 | nopts.cols = 1; 28 | struct ncplane* n = ncplane_create(n_, &nopts); 29 | REQUIRE(nullptr != n); 30 | struct ncmultiselector* ns = ncmultiselector_create(n, &s); 31 | REQUIRE(ns); 32 | CHECK(0 == notcurses_render(nc_)); 33 | } 34 | 35 | // now do the same, but with a plane we have created. 36 | SUBCASE("RefuseBoundCreatedPlane") { 37 | struct ncplane_options nopts{}; 38 | nopts.rows = ncplane_dim_y(n_); 39 | nopts.cols = ncplane_dim_x(n_); 40 | auto ncp = ncplane_create(n_, &nopts); 41 | REQUIRE(nullptr != ncp); 42 | ncmultiselector_options s{}; 43 | struct ncmultiselector* ns = ncmultiselector_create(ncp, &s); 44 | REQUIRE(ns); 45 | CHECK(0 == notcurses_render(nc_)); 46 | struct ncmultiselector* fail = ncmultiselector_create(ncp, &s); 47 | CHECK(nullptr == fail); 48 | CHECK(0 == notcurses_render(nc_)); 49 | } 50 | 51 | CHECK(0 == notcurses_stop(nc_)); 52 | } 53 | -------------------------------------------------------------------------------- /src/tests/output.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | TEST_CASE("Output") { 4 | auto nc_ = testing_notcurses(); 5 | if(!nc_){ 6 | return; 7 | } 8 | ncplane* n_ = notcurses_stdplane(nc_); 9 | REQUIRE(n_); 10 | 11 | // we ought be able to fill up the plane using any alignment, even if we 12 | // spill over 13 | SUBCASE("AlignLeftFull") { 14 | struct ncplane_options nopts{}; 15 | nopts.rows = 1; 16 | nopts.cols = 10; 17 | auto n = ncplane_create(n_, &nopts); 18 | REQUIRE(n); 19 | CHECK(-10 == ncplane_putstr_aligned(n, 0, NCALIGN_LEFT, "0123456789L")); 20 | CHECK(0 == notcurses_render(nc_)); 21 | for(unsigned x = 0 ; x < ncplane_dim_x(n) ; ++x){ 22 | auto egc = notcurses_at_yx(nc_, 0, x, nullptr, nullptr); 23 | char expected[2] = {0}; 24 | REQUIRE(egc); 25 | expected[0] = x + '0'; 26 | CHECK(0 == strcmp(egc, expected)); 27 | free(egc); 28 | } 29 | CHECK(0 == ncplane_destroy(n)); 30 | } 31 | 32 | // we ought be able to fill up the plane using any alignment, even if we 33 | // spill over 34 | SUBCASE("AlignRightFull") { 35 | struct ncplane_options nopts{}; 36 | nopts.rows = 1; 37 | nopts.cols = 10; 38 | auto n = ncplane_create(n_, &nopts); 39 | REQUIRE(n); 40 | CHECK(-10 == ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "0123456789L")); 41 | CHECK(0 == notcurses_render(nc_)); 42 | for(unsigned x = 0 ; x < ncplane_dim_x(n) ; ++x){ 43 | auto egc = notcurses_at_yx(nc_, 0, x, nullptr, nullptr); 44 | char expected[2] = {0}; 45 | REQUIRE(egc); 46 | expected[0] = x + '0'; 47 | CHECK(0 == strcmp(egc, expected)); 48 | free(egc); 49 | } 50 | CHECK(0 == ncplane_destroy(n)); 51 | } 52 | 53 | CHECK(0 == notcurses_stop(nc_)); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/tests/reader.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include 3 | #include 4 | 5 | TEST_CASE("Readers") { 6 | auto nc_ = testing_notcurses(); 7 | if(!nc_){ 8 | return; 9 | } 10 | unsigned dimx, dimy; 11 | struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx); 12 | REQUIRE(n_); 13 | REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); 14 | 15 | SUBCASE("ReaderRender") { 16 | ncreader_options opts{}; 17 | struct ncplane_options nopts = { 18 | .y = 0, 19 | .x = 0, 20 | .rows = dimy / 2, 21 | .cols = dimx / 2, 22 | .userptr = nullptr, 23 | .name = nullptr, 24 | .resizecb = nullptr, 25 | .flags = 0, 26 | .margin_b = 0, .margin_r = 0, 27 | }; 28 | auto ncp = ncplane_create(notcurses_stdplane(nc_), &nopts); 29 | uint64_t echannels = NCCHANNELS_INITIALIZER(0xff, 0x44, 0xff, 0, 0, 0); 30 | ncplane_set_base(ncp, notcurses_canutf8(nc_) ? "\u2592" : "x", 0, echannels); 31 | auto nr = ncreader_create(ncp, &opts); 32 | REQUIRE(nullptr != nr); 33 | CHECK(0 == notcurses_render(nc_)); 34 | char* contents = nullptr; 35 | ncreader_destroy(nr, &contents); 36 | REQUIRE(contents); 37 | free(contents); 38 | CHECK(0 == notcurses_render(nc_)); 39 | } 40 | 41 | CHECK(0 == notcurses_stop(nc_)); 42 | } 43 | -------------------------------------------------------------------------------- /src/tests/version.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | TEST_CASE("Version") { 4 | auto nc_ = testing_notcurses(); 5 | REQUIRE(nullptr != nc_); 6 | int major, minor, patch, tweak; 7 | notcurses_version_components(&major, &minor, &patch, &tweak); 8 | CHECK(atoi(NOTCURSES_VERSION_MAJOR) == major); 9 | CHECK(atoi(NOTCURSES_VERSION_MINOR) == minor); 10 | CHECK(atoi(NOTCURSES_VERSION_PATCH) == patch); 11 | CHECK(atoi(NOTCURSES_VERSION_TWEAK) == tweak); 12 | CHECK(0 == notcurses_stop(nc_)); 13 | } 14 | -------------------------------------------------------------------------------- /src/tetris/clear.h: -------------------------------------------------------------------------------- 1 | // returns true iff the specified row of the board is clear (full with no gaps) 2 | bool LineClear(int y){ 3 | int dimx = board_->get_dim_x(); 4 | for(int x = 1 ; x < dimx - 1 ; ++x){ 5 | ncpp::Cell c; 6 | board_->get_at(y, x, &c); 7 | if(strcmp(board_->get_extended_gcluster(c), "") == 0){ 8 | return false; 9 | } 10 | } 11 | return true; 12 | } 13 | -------------------------------------------------------------------------------- /src/tetris/gravity.h: -------------------------------------------------------------------------------- 1 | static constexpr int MAX_LEVEL = 16; 2 | // the number of milliseconds before a drop is forced at the given level, 3 | // using the NES fps counter of 50ms 4 | static constexpr int Gravity(int level) { 5 | constexpr int MS_PER_GRAV = 30; // 10MHz*63/88/455/525 (~29.97fps) in NTSC 6 | // The number of frames before a drop is forced, per level 7 | constexpr std::array Gravities = { 8 | 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 4, 4, 3, 2, 1 9 | }; 10 | if(level < 0){ 11 | throw std::out_of_range("Illegal level"); 12 | } 13 | if(static_cast(level) < Gravities.size()){ 14 | return Gravities[level] * MS_PER_GRAV; 15 | } 16 | return MS_PER_GRAV; // all levels 29+ are a single grav 17 | } 18 | -------------------------------------------------------------------------------- /src/tetris/lock.h: -------------------------------------------------------------------------------- 1 | bool LockPiece(){ // returns true if game has ended by reaching level 16 2 | curpiece_->mergedown_simple(*board_); 3 | unsigned bdimy, bdimx; 4 | board_->get_dim(&bdimy, &bdimx); 5 | int cleared; // how many contiguous lines were cleared 6 | do{ 7 | cleared = 0; 8 | int y; 9 | StainBoard(bdimy, bdimx); 10 | for(y = bdimy - 2 ; y > 0 ; --y){ // get the lowest cleared area 11 | if(LineClear(y)){ 12 | ++cleared; 13 | }else if(cleared){ 14 | break; 15 | } 16 | } 17 | if(cleared){ // topmost verified clear is y + 1, bottommost is y + cleared 18 | for(int dy = y ; dy >= 0 ; --dy){ 19 | for(unsigned x = 1 ; x < bdimx - 1 ; ++x){ 20 | ncpp::Cell c; 21 | board_->get_at(dy, x, &c); 22 | board_->putc(dy + cleared, x, &c); 23 | c.get().gcluster = 0; 24 | board_->putc(dy, x, &c); // could just do this at end... 25 | } 26 | } 27 | linescleared_ += cleared; 28 | static constexpr int points[] = {50, 150, 350, 1000}; 29 | score_ += (level_) * points[cleared - 1]; 30 | if((level_ = linescleared_ / 10 + 1) > MAX_LEVEL){ 31 | return true; 32 | } 33 | mtx_.lock(); 34 | msdelay_ = std::chrono::milliseconds(Gravity(level_)); 35 | mtx_.unlock(); 36 | StainBoard(bdimy, bdimx); 37 | UpdateScore(); 38 | } 39 | }while(cleared); 40 | return false; 41 | } 42 | -------------------------------------------------------------------------------- /src/tetris/main.cpp: -------------------------------------------------------------------------------- 1 | #define NCPP_EXCEPTIONS_PLEASE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "compat/compat.h" 15 | #include "builddef.h" 16 | #include "version.h" 17 | 18 | std::mutex ncmtx; 19 | 20 | const std::string BackgroundFile = notcurses_data_path(nullptr, "tetris-background.jpg"); 21 | const std::string LogoFile = notcurses_data_path(nullptr, "notcurses.png"); 22 | 23 | using namespace std::chrono_literals; 24 | 25 | class Tetris { 26 | public: 27 | Tetris(ncpp::NotCurses& nc, std::atomic_bool& gameover) : 28 | nc_(nc), 29 | score_(0), 30 | curpiece_(nullptr), 31 | board_(nullptr), 32 | backg_(nullptr), 33 | stdplane_(nc_.get_stdplane()), 34 | scoreplane_(nullptr), 35 | gameover_(gameover), 36 | level_(1), 37 | linescleared_(0), 38 | msdelay_(Gravity(level_)) 39 | { 40 | DrawBoard(); 41 | curpiece_ = NewPiece(); 42 | } 43 | 44 | // 0.5 cell aspect: 1 board height == one row. 1 board width == two columns. 45 | static constexpr auto BOARD_WIDTH = 10; 46 | static constexpr auto BOARD_HEIGHT = 20; 47 | 48 | #include "gravity.h" 49 | #include "ticker.h" 50 | #include "score.h" 51 | #include "clear.h" 52 | #include "stain.h" 53 | #include "lock.h" 54 | #include "movedown.h" 55 | #include "movelateral.h" 56 | #include "rotate.h" 57 | 58 | private: 59 | ncpp::NotCurses& nc_; 60 | uint64_t score_; 61 | std::mutex mtx_; // guards msdelay_ 62 | std::unique_ptr curpiece_; 63 | std::unique_ptr board_; 64 | std::unique_ptr logop_; 65 | std::unique_ptr backg_; 66 | ncpp::Plane* stdplane_; 67 | std::unique_ptr scoreplane_; 68 | std::atomic_bool& gameover_; 69 | int board_top_y_; 70 | int level_; 71 | int linescleared_; 72 | std::chrono::milliseconds msdelay_; 73 | 74 | // Returns true if there's a current piece which can be moved 75 | auto PrepForMove(int* y, int* x) -> bool { 76 | if(!curpiece_){ 77 | return false; 78 | } 79 | curpiece_->get_yx(y, x); 80 | return true; 81 | } 82 | 83 | #include "background.h" 84 | #include "stuck.h" 85 | #include "newpiece.h" 86 | 87 | }; 88 | 89 | #include "main.h" 90 | -------------------------------------------------------------------------------- /src/tetris/main.h: -------------------------------------------------------------------------------- 1 | bool IOLoop(ncpp::NotCurses& nc, Tetris& t, std::atomic_bool& gameover) { 2 | ncpp::Plane* stdplane = nc.get_stdplane(); 3 | char32_t input = 0; 4 | ncinput ni; 5 | while(!gameover && (input = nc.get(true, &ni)) != (char32_t)-1){ 6 | if(input == 'q'){ 7 | break; 8 | } 9 | if(ni.evtype == ncpp::EvType::Release){ 10 | continue; 11 | } 12 | ncmtx.lock(); 13 | switch(input){ 14 | case NCKEY_LEFT: case 'h': t.MoveLeft(); break; 15 | case NCKEY_RIGHT: case 'l': t.MoveRight(); break; 16 | case NCKEY_DOWN: case 'j': { if(t.MoveDown()){ gameover = true; } break; } 17 | case 'L': if(ni.ctrl){ nc.refresh(nullptr, nullptr); } break; 18 | case 'z': t.RotateCcw(); break; 19 | case 'x': t.RotateCw(); break; 20 | default: 21 | stdplane->cursor_move(0, 0); 22 | stdplane->printf("Got unknown input U+%06x", input); 23 | nc.render(); 24 | break; 25 | } 26 | ncmtx.unlock(); 27 | } 28 | return gameover || input == 'q'; 29 | } 30 | 31 | int main(void) { 32 | if(setlocale(LC_ALL, "") == nullptr){ 33 | return EXIT_FAILURE; 34 | } 35 | srand(time(nullptr)); 36 | std::atomic_bool gameover = false; 37 | notcurses_options ncopts{}; 38 | ncopts.flags = NCOPTION_INHIBIT_SETLOCALE; 39 | ncpp::NotCurses nc(ncopts); 40 | { 41 | Tetris t{nc, gameover}; 42 | std::thread tid(&Tetris::Ticker, &t); 43 | if(IOLoop(nc, t, gameover)){ 44 | gameover = true; // FIXME signal thread 45 | tid.join(); 46 | }else{ 47 | return EXIT_FAILURE; 48 | } 49 | } 50 | return nc.stop() ? EXIT_SUCCESS : EXIT_FAILURE; 51 | } 52 | -------------------------------------------------------------------------------- /src/tetris/movedown.h: -------------------------------------------------------------------------------- 1 | bool MoveDown() { // returns true if the game has ended as a result of this move 2 | int y, x; 3 | if(PrepForMove(&y, &x)){ 4 | curpiece_->move(y + 1, x); 5 | if(InvalidMove()){ 6 | curpiece_->move(y, x); 7 | if(y <= board_top_y_ - 1){ 8 | return true; 9 | } 10 | if(LockPiece()){ 11 | return true; 12 | } 13 | curpiece_ = NewPiece(); 14 | }else{ 15 | ++y; 16 | } 17 | nc_.render(); 18 | } 19 | return false; 20 | } 21 | -------------------------------------------------------------------------------- /src/tetris/movelateral.h: -------------------------------------------------------------------------------- 1 | void MoveLateral(int direction) { // pass in -1 for left, 1 for right 2 | int shift = 2 * direction; 3 | int y, x; 4 | if(PrepForMove(&y, &x)){ 5 | curpiece_->move(y, x + shift); 6 | if(InvalidMove()){ 7 | curpiece_->move(y, x); 8 | }else{ 9 | x += shift; 10 | nc_.render(); 11 | } 12 | } 13 | } 14 | 15 | inline void MoveLeft() { 16 | MoveLateral(-1); 17 | } 18 | 19 | inline void MoveRight() { 20 | MoveLateral(1); 21 | } 22 | -------------------------------------------------------------------------------- /src/tetris/newpiece.h: -------------------------------------------------------------------------------- 1 | // tidx is an index into tetriminos. yoff and xoff are relative to the 2 | // terminal's origin. returns colored north-facing tetrimino on a plane. 3 | std::unique_ptr NewPiece() { 4 | // "North-facing" tetrimino forms (form in which they are released from the top) are expressed in terms of 5 | // two rows having between 2 and 4 columns. We map each game column to four columns and each game row to two 6 | // rows. Each byte of the texture maps to one 4x4 component block (and wastes 7 bits). 7 | static const struct tetrimino { 8 | unsigned color; 9 | const char* texture; 10 | } tetriminos[] = { // OITLJSZ 11 | { 0xcbc900, "****"}, { 0x009caa, " ****"}, { 0x952d98, " * ***"}, { 0xcf7900, " ****"}, 12 | { 0x0065bd, "* ***"}, { 0x69be28, " **** "}, { 0xbd2939, "** **"} }; 13 | const int tidx = rand() % 7; 14 | const struct tetrimino* t = &tetriminos[tidx]; 15 | const size_t cols = strlen(t->texture); 16 | unsigned y, x; 17 | stdplane_->get_dim(&y, &x); 18 | const int xoff = x / 2 - BOARD_WIDTH + 2 * (rand() % (BOARD_WIDTH / 2)); 19 | std::unique_ptr n = std::make_unique(2, cols, board_top_y_ - 1, xoff, nullptr); 20 | if(n){ 21 | uint64_t channels = 0; 22 | ncchannels_set_bg_alpha(&channels, NCALPHA_TRANSPARENT); 23 | ncchannels_set_fg_alpha(&channels, NCALPHA_TRANSPARENT); 24 | n->set_fg_rgb(t->color); 25 | n->set_bg_alpha(NCALPHA_TRANSPARENT); 26 | n->set_base("", 0, channels); 27 | y = 0; x = 0; 28 | for(size_t i = 0 ; i < strlen(t->texture) ; ++i){ 29 | if(t->texture[i] == '*'){ 30 | n->putstr(y, x, "██"); 31 | } 32 | y += ((x = ((x + 2) % cols)) == 0); 33 | } 34 | } 35 | nc_.render(); 36 | return n; 37 | } 38 | -------------------------------------------------------------------------------- /src/tetris/rotate.h: -------------------------------------------------------------------------------- 1 | void RotateCcw() { 2 | int y, x; 3 | if(!PrepForMove(&y, &x)){ 4 | return; 5 | } 6 | curpiece_->rotate_ccw(); 7 | if(InvalidMove()){ 8 | curpiece_->rotate_cw(); 9 | } 10 | nc_.render(); 11 | } 12 | 13 | void RotateCw() { 14 | int y, x; 15 | if(!PrepForMove(&y, &x)){ 16 | return; 17 | } 18 | curpiece_->rotate_cw(); 19 | if(InvalidMove()){ 20 | curpiece_->rotate_ccw(); 21 | } 22 | nc_.render(); 23 | } 24 | -------------------------------------------------------------------------------- /src/tetris/score.h: -------------------------------------------------------------------------------- 1 | void UpdateScore(){ 2 | scoreplane_->printf(1, 0, "level: %02d score: %" PRIu64, level_, score_); 3 | } 4 | -------------------------------------------------------------------------------- /src/tetris/stain.h: -------------------------------------------------------------------------------- 1 | void StainBoard(int dimy, int dimx){ 2 | board_->cursor_move(0, 1); 3 | const int l = level_ - 1; 4 | int high = 0xff - (l / 2) * 0x10; 5 | int low = l * 0x10; 6 | int green = 0; 7 | if(low >= 0x100){ 8 | low = low % 0x100; 9 | } 10 | green = (l / 2) * 0x20; 11 | const int c1 = level_ % 2 ? high : low; 12 | const int c2 = level_ % 2 ? low : high; 13 | uint64_t tl = NCCHANNELS_INITIALIZER(c1, green, c2, c1, green, c2); 14 | uint64_t tr = NCCHANNELS_INITIALIZER(c2, green, c1, c2, green, c1); 15 | uint64_t bl = NCCHANNELS_INITIALIZER(c2, green, c1, c2, green, c1); 16 | uint64_t br = NCCHANNELS_INITIALIZER(c1, green, c2, c1, green, c2); 17 | board_->stain(0, 1, dimy - 1, dimx - 2, tl, tr, bl, br); 18 | } 19 | -------------------------------------------------------------------------------- /src/tetris/stuck.h: -------------------------------------------------------------------------------- 1 | bool InvalidMove() { // a bit wasteful, but pieces are tiny 2 | unsigned dy, dx; 3 | curpiece_->get_dim(&dy, &dx); 4 | while(dy--){ 5 | int x = dx; 6 | while(x--){ 7 | ncpp::Cell c, b; 8 | curpiece_->get_at(dy, x, &c); 9 | if(strcmp(curpiece_->get_extended_gcluster(c), "") == 0){ 10 | continue; 11 | } 12 | curpiece_->release(c); 13 | int transy = dy, transx = x; // need game area coordinates via translation 14 | curpiece_->translate(*board_, &transy, &transx); 15 | if(transy < 0 || (unsigned)transy >= board_->get_dim_y() 16 | || transx < 0 || (unsigned)transx >= board_->get_dim_x()){ 17 | return true; 18 | } 19 | board_->get_at(transy, transx, &b); 20 | if(strcmp(board_->get_extended_gcluster(b), "")){ 21 | return true; 22 | } 23 | board_->release(b); 24 | } 25 | } 26 | return false; 27 | } 28 | -------------------------------------------------------------------------------- /src/tetris/ticker.h: -------------------------------------------------------------------------------- 1 | void Ticker() { // FIXME ideally this would be called from constructor :/ 2 | std::chrono::milliseconds ms; 3 | do{ 4 | mtx_.lock(); 5 | ms = msdelay_; 6 | mtx_.unlock(); 7 | std::this_thread::sleep_for(ms); 8 | ncmtx.lock(); 9 | if(MoveDown()){ 10 | gameover_ = true; 11 | ncmtx.unlock(); 12 | return; 13 | } 14 | ncmtx.unlock(); 15 | }while(!gameover_); 16 | } 17 | -------------------------------------------------------------------------------- /tools/Notcurses++Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | set(Notcurses++_DIR "@PACKAGE_SOME_INSTALL_DIR@") 3 | 4 | # Compute paths 5 | get_filename_component(Notcurses_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 6 | set(Notcurses++_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") 7 | set(Notcurses++_LIBRARY_DIRS "@CONF_LIBRARY_DIRS@") 8 | 9 | set(Notcurses++_LIBRARIES -lnotcurses -lnotcurses++) 10 | -------------------------------------------------------------------------------- /tools/NotcursesConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | set(Notcurses_DIR "@PACKAGE_SOME_INSTALL_DIR@") 3 | 4 | # Compute paths 5 | get_filename_component(Notcurses_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 6 | set(Notcurses_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") 7 | set(Notcurses_LIBRARY_DIRS "@CONF_LIBRARY_DIRS@") 8 | 9 | set(Notcurses_LIBRARIES -lnotcurses-core -lnotcurses) 10 | -------------------------------------------------------------------------------- /tools/NotcursesCoreConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | set(Notcurses_DIR "@PACKAGE_SOME_INSTALL_DIR@") 3 | 4 | # Compute paths 5 | get_filename_component(Notcurses_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 6 | set(Notcurses_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") 7 | set(Notcurses_LIBRARY_DIRS "@CONF_LIBRARY_DIRS@") 8 | 9 | set(Notcurses_LIBRARIES -lnotcurses-core) 10 | -------------------------------------------------------------------------------- /tools/builddef.h.in: -------------------------------------------------------------------------------- 1 | // Populated by CMake; not installed 2 | 3 | // if we're a DFSG build, we leave out references to certain demos 4 | #cmakedefine DFSG_BUILD 5 | 6 | // if we're an ASAN build, we don't use sigaltstack() ourselves 7 | #cmakedefine USE_ASAN 8 | #cmakedefine USE_DEFLATE 9 | #cmakedefine USE_GPM 10 | #cmakedefine USE_QRCODEGEN 11 | // exclusive with USE_OIIO 12 | #cmakedefine USE_FFMPEG 13 | // exclusive with USE_FFMPEG 14 | #cmakedefine USE_OIIO 15 | // set if either USE_FFMPEG || USE_OIIO 16 | #if defined(USE_FFMPEG) || defined(USE_OIIO) 17 | #define NOTCURSES_USE_MULTIMEDIA 18 | #endif 19 | #define NOTCURSES_SHARE "@CMAKE_INSTALL_FULL_DATADIR@/notcurses" 20 | -------------------------------------------------------------------------------- /tools/debrelease.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # export DISTRIBUTION to use something other than unstable (or whatever was 6 | # last used in debian/changelog). see dch(1). can use a DEBVERSION exported 7 | # in the process's environment. 8 | usage() { echo "usage: `basename $0` version notcursessrcdir" ; } 9 | 10 | [ $# -eq 2 ] || { usage >&2 ; exit 1 ; } 11 | 12 | VERSION="$1" 13 | SRCDIR="$2" 14 | 15 | if [ -z "$DEBVERSION" ] ; then 16 | DEBVERSION=1 17 | fi 18 | 19 | rm -fv debian/files 20 | dch -v $VERSION+dfsg-$DEBVERSION 21 | if [ -n "$DISTRIBUTION" ] ; then 22 | dch -r --distribution "$DISTRIBUTION" 23 | else 24 | dch -r 25 | fi 26 | uscan --repack --compression xz --force 27 | XBALL=../notcurses_$VERSION+dfsg.orig.tar.xz 28 | gpg --sign --armor --detach-sign $XBALL 29 | ASC=$(readlink -f $XBALL.asc) 30 | XBALL=$(readlink -f $XBALL) # eliminates ../ 31 | cd "$SRCDIR" 32 | gh release upload v$VERSION $ASC $XBALL 33 | cd - 34 | git commit -m "v$VERSION" -a 35 | 36 | gbp import-orig --upstream-version=$VERSION ../notcurses_$VERSION+dfsg.orig.tar.xz 37 | git push --tags 38 | dpkg-buildpackage --build=source 39 | cd .. 40 | xterm -e sudo pbuilder build notcurses*dsc 41 | cd - 42 | git push 43 | rm debian/files 44 | -------------------------------------------------------------------------------- /tools/emojiprep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # Used to generate C constants from a Unicode Consortium 6 | # emoji-ordering-rules.txt data file. This is done to build 7 | # the mojibake demo C file. 8 | 9 | usage() { echo "usage: `basename $0` < emoji-ordering-rules.txt" ; } 10 | 11 | [ "$#" -eq 0 ] || { usage >&2 ; exit 1 ; } 12 | 13 | while read line ; do unicode --brief --max 100 $line | cut -d\ -f2 | \ 14 | sed -e 's/U+\(.....\)/\\U000\1/' | \ 15 | sed -e 's/U+\(....\)/\\u\1/' | \ 16 | sed -e ':a; /u200D$/N; s/u200D\n/u200D/; ta' | \ 17 | sed -e ':a; $!N;s/\n\\u200D/\\u200D/;ta;P;D' | \ 18 | sed -e 's/\(.*\)/"\1"/' 19 | done 20 | -------------------------------------------------------------------------------- /tools/function-table.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # Extract a list of the public API, both shared object functions and those 6 | # static inline functions in the public headers. 7 | 8 | usage () { echo "usage: `basename $0` notcurses-dir" ; } 9 | 10 | [ $# -eq 1 ] || { usage >&2 ; exit 1 ; } 11 | NCDIR="$1" 12 | [ -d "$NCDIR" ] || { usage >&2 ; exit 1 ; } 13 | 14 | generate_lists () { 15 | grep -h ^API "$1"/include/notcurses/*.h | grep -v inline | sort 16 | grep -h -A1 ^API\ inline "$1"/include/notcurses/*.h | \ 17 | sed -e '/^--$/d' -e 'N;s/\n/ /' -e 's/\(.*\){$/\1;/' | sort 18 | } 19 | 20 | generate_lists "$NCDIR" | sed -e 's/RESTRICT/restrict/g' 21 | -------------------------------------------------------------------------------- /tools/generate_ffi.py: -------------------------------------------------------------------------------- 1 | import re 2 | import glob 3 | import os 4 | import sys 5 | 6 | match_static_inline = re.compile(r'static inline (.*?)\n([\S\s][^;]*?){') 7 | 8 | def generate_ffi(notcurses_dir): 9 | lines = [] 10 | for file in glob.glob(os.path.join(notcurses_dir, "include", "notcurses", "*.h")): 11 | with open(file, 'r') as f: 12 | content = f.read() 13 | finds = re.findall(match_static_inline, content) 14 | for find in finds: 15 | lines.append(find[0] + ' ' + find[1] + ';') 16 | 17 | lines.sort() 18 | 19 | with open(os.path.join(notcurses_dir, "src", "libffi", "ffi.c"), 'w') as f: 20 | f.write("// Contains all inline functions in include/notcurses/*.h\n") 21 | f.write("// This file is auto generated from tools/generate_ffi.py\n") 22 | f.write("#include \n") 23 | f.write("#include \n\n") 24 | f.write("#include \n\n") 25 | 26 | for line in lines: 27 | line = line.replace("RESTRICT", "restrict") 28 | f.write(line) 29 | f.write('\n') 30 | 31 | if __name__ == "__main__": 32 | if len(sys.argv) != 2: 33 | print("usage: generate_ffi.py notcurses-dir") 34 | else: 35 | generate_ffi(sys.argv[1]) 36 | -------------------------------------------------------------------------------- /tools/interactive-tester.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # interactive tester for Notcurses. runs a variety of programs, which the 6 | # user must inspect for correct output -- i.e. these do not check their 7 | # own output for correctness =[. it ought be run from a notcurses build 8 | # directory, with all binaries built. 9 | 10 | DATA=../data # FIXME 11 | OUT=$(basename 0).log # FIXME 12 | rm -f "$OUT" 13 | 14 | [ -d "$DATA" ] || { echo "$DATA was not a directory" >&2 ; exit 1 ; } 15 | 16 | # this ought process the entire file, then allow the user to exit with ^D 17 | ./notcurses-input -v < ../src/lib/in.c 2>>"$OUT" 18 | 19 | # goes through a series of self-described bitmap frames 20 | ./bitmapstates 2>>"$OUT" 21 | 22 | ./statepixel "$DATA"/worldmap.jpg 2>>"$OUT" 23 | 24 | ./ncneofetch -v 2>>"$OUT" 25 | 26 | ./resize 27 | -------------------------------------------------------------------------------- /tools/notcurses++.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 5 | 6 | Name: @PROJECT_NAME@++ 7 | Description: C++ bindings for notcurses 8 | Version: @PROJECT_VERSION@ 9 | 10 | Requires: notcurses >= @PROJECT_VERSION@ 11 | Libs: -L${libdir} -lnotcurses -lnotcurses++ 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /tools/notcurses-core.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 5 | 6 | Name: @PROJECT_NAME@-core 7 | Description: TUI library for modern terminal emulators (core library) 8 | Version: @PROJECT_VERSION@ 9 | 10 | Requires: 11 | Requires.private: @PKGCONF_REQ_PRIV@ 12 | Libs: -L${libdir} -lnotcurses-core 13 | Libs.private: -lunistring -lm 14 | Cflags: -I${includedir} 15 | -------------------------------------------------------------------------------- /tools/notcurses-ffi.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 5 | 6 | Name: @PROJECT_NAME@ 7 | Description: TUI library for modern terminal emulators (ffi library) 8 | Version: @PROJECT_VERSION@ 9 | 10 | Requires: notcurses-ffi 11 | Requires.private: 12 | Libs: -L${libdir} -lnotcurses-ffi 13 | Libs.private: -lunistring -lm 14 | Cflags: -I${includedir} 15 | -------------------------------------------------------------------------------- /tools/notcurses.guix: -------------------------------------------------------------------------------- 1 | (define-module (gnu packages notcurses) 2 | #:use-module (guix packages) 3 | #:use-module (guix download) 4 | #:use-module (guix build-system gnu) 5 | #:use-module (guix licenses) 6 | #:use-module (gnu packages gawk)) 7 | 8 | (define-public notcurses 9 | (package 10 | (name "notcurses") 11 | (version "2.3.1") 12 | (source (origin 13 | (method git-fetch) 14 | (uri (git-reference "https://github.com/dankamongmen/notcurses" version 15 | ".tar.gz")) 16 | (sha256 17 | (base32 18 | "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))) 19 | (build-system cmake) 20 | (arguments '(#:configure-flags '("-DUSE_POC=off"))) 21 | (synopsis "Blingful library for TUIs and character semigraphics") 22 | (description "Blingful library for TUIs and character semigraphics") 23 | (home-page "https://notcurses.com") 24 | (license asl2.0))) 25 | -------------------------------------------------------------------------------- /tools/notcurses.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 5 | 6 | Name: @PROJECT_NAME@ 7 | Description: TUI library for modern terminal emulators (multimedia support) 8 | Version: @PROJECT_VERSION@ 9 | 10 | Requires: notcurses-core 11 | Requires.private: 12 | Libs: -L${libdir} -lnotcurses 13 | Libs.private: -lstdc++ 14 | Cflags: -I${includedir} 15 | -------------------------------------------------------------------------------- /tools/nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Notcurses 6 | 3.0.16 7 | Notcurses TUI/CLI library 8 | Library for blingful TUIs and character graphics 9 | nick black 10 | https://notcurses.com 11 | Apache-2.0 12 | copyright 2019–2022 nick black 13 | false 14 | 15 | tui graphics cli 16 | icon.png 17 | README.md 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /tools/setup.cfg.in: -------------------------------------------------------------------------------- 1 | [nosetests] 2 | verbosity=1 3 | detailed-errors=1 4 | with-coverage=1 5 | cover-package=nose 6 | debug=nose.loader 7 | pdb=1 8 | pdb-failures=1 9 | -------------------------------------------------------------------------------- /tools/setup.py.in: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import os 3 | 4 | def read(fname): 5 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 6 | 7 | setup( 8 | name="notcurses", 9 | version="${PROJECT_VERSION}", 10 | packages=['notcurses'], 11 | package_dir={ '': '${CMAKE_CURRENT_BINARY_DIR}/python/src' }, 12 | author="Nick Black", 13 | author_email="nickblack@linux.com", 14 | description="Blingful TUI construction library (python bindings)", 15 | keywords="ncurses curses tui console graphics", 16 | license='Apache License, Version 2.0', 17 | url='https://github.com/dankamongmen/notcurses', 18 | include_dirs=['${CMAKE_CURRENT_SOURCE_DIR}/include'], 19 | long_description=read('${CMAKE_CURRENT_SOURCE_DIR}/README.md'), 20 | zip_safe=True, 21 | platforms=["any"], 22 | long_description_content_type="text/markdown", 23 | install_requires=["cffi>=1.0.0"], 24 | setup_requires=["cffi>=1.0.0"], 25 | cffi_modules=['${CMAKE_CURRENT_BINARY_DIR}/python/src/notcurses/build_notcurses.py:ffibuild'], 26 | # see https://pypi.org/pypi?%3Aaction=list_classifiers 27 | classifiers=[ 28 | 'Development Status :: 4 - Beta', 29 | 'Environment :: Console', 30 | 'License :: OSI Approved :: Apache Software License', 31 | 'Natural Language :: English', 32 | 'Programming Language :: Python', 33 | ], 34 | ) 35 | -------------------------------------------------------------------------------- /tools/version.h.in: -------------------------------------------------------------------------------- 1 | // Populated by CMake, and installed to the host system 2 | #ifndef NOTCURSES_VERSION_HEADER 3 | #define NOTCURSES_VERSION_HEADER 4 | 5 | #define NOTCURSES_VERNUM_MAJOR @notcurses_VERSION_MAJOR@ 6 | #define NOTCURSES_VERNUM_MINOR @notcurses_VERSION_MINOR@ 7 | #define NOTCURSES_VERNUM_PATCH @notcurses_VERSION_PATCH@ 8 | #define NOTCURSES_VERNUM_TWEAK @notcurses_VERSION_TWEAK@ 9 | 10 | #define NOTCURSES_VERSION_COMPARABLE(major, minor, patch) \ 11 | (((major) << 16u) + ((minor) << 8u) + (patch)) 12 | 13 | #define NOTCURSES_VERNUM_ORDERED NOTCURSES_VERSION_COMPARABLE( \ 14 | NOTCURSES_VERNUM_MAJOR, NOTCURSES_VERNUM_MINOR, NOTCURSES_VERNUM_PATCH) 15 | 16 | #define NOTCURSES_VERSION_MAJOR "@notcurses_VERSION_MAJOR@" 17 | #define NOTCURSES_VERSION_MINOR "@notcurses_VERSION_MINOR@" 18 | #define NOTCURSES_VERSION_PATCH "@notcurses_VERSION_PATCH@" 19 | #define NOTCURSES_VERSION_TWEAK "@notcurses_VERSION_TWEAK@" 20 | 21 | #endif 22 | --------------------------------------------------------------------------------