2 Commits

Author SHA1 Message Date
Alex
49ac5e546a Merge baa5973128 into ba81d364cf 2025-06-02 15:23:28 +03:00
alexv-ds
baa5973128 msvc getenv deprecation warn fix 2024-07-18 18:34:34 +03:00
156 changed files with 1007 additions and 3323 deletions

View File

@@ -1,5 +1,3 @@
common --enable_bzlmod
build --features=layering_check
build --enable_bzlmod

View File

@@ -2,6 +2,3 @@
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Chromium
Standard: Cpp11
InsertBraces: true
InsertNewlineAtEOF: true

View File

@@ -165,47 +165,3 @@ jobs:
flags: ${{ runner.os }}
name: ${{ runner.os }}-coverage
files: ./build/coverage.xml
test_modules:
name: "Test modules"
strategy:
matrix:
include:
- os: ubuntu-latest
compiler: llvm
# TODO add gcc / msvc
runs-on: ${{ matrix.os }}
steps:
- name: "Checkout repository"
uses: actions/checkout@v3
- name: "Setup Cpp"
uses: aminya/setup-cpp@v1
with:
compiler: ${{ matrix.compiler }}
vcvarsall: ${{ contains(matrix.os, 'windows' )}}
cmake: true
ninja: true
clangtidy: false
cppcheck: false
opencppcoverage: false
- name: "Generate ./examples_modules"
run: >
./tools/generate_examples_modules.sh
- name: "Build modules"
run: >
mkdir build;
cd build;
cmake ..
-DCMAKE_GENERATOR=Ninja
-DFTXUI_BUILD_MODULES=ON
-DFTXUI_BUILD_EXAMPLES=ON
-DCMAKE_BUILD_TYPE=Debug
-DFTXUI_BUILD_DOCS=OFF
-DFTXUI_BUILD_TESTS=OFF
-DFTXUI_BUILD_TESTS_FUZZER=OFF
-DFTXUI_ENABLE_INSTALL=ON
-DFTXUI_DEV_WARNINGS=ON ;
cmake --build .

2
.gitignore vendored
View File

@@ -62,10 +62,8 @@ out/
!include/ftxui/**/*.cpp
# src directory:
!src/ftxui/*.cppm
!src/ftxui/**/*.hpp
!src/ftxui/**/*.cpp
!src/ftxui/**/*.cppm
# tools directory:
!tools/**/*.sh

View File

@@ -13,6 +13,7 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load(":bazel/ftxui.bzl", "ftxui_cc_library")
load(":bazel/ftxui.bzl", "generate_examples")
load(":bazel/ftxui.bzl", "windows_copts")
load(":bazel/ftxui.bzl", "pthread_linkopts")
# A meta target depending on all of the ftxui submodules.
# Note that component depends on dom and screen, so ftxui is just an alias for
@@ -158,12 +159,6 @@ ftxui_cc_library(
"src/ftxui/component/resizable_split.cpp",
"src/ftxui/component/screen_interactive.cpp",
"src/ftxui/component/slider.cpp",
"src/ftxui/component/task.cpp",
"src/ftxui/component/task_internal.hpp",
"src/ftxui/component/task_queue.cpp",
"src/ftxui/component/task_queue.hpp",
"src/ftxui/component/task_runner.cpp",
"src/ftxui/component/task_runner.hpp",
"src/ftxui/component/terminal_input_parser.cpp",
"src/ftxui/component/terminal_input_parser.hpp",
"src/ftxui/component/util.cpp",
@@ -175,9 +170,6 @@ ftxui_cc_library(
# Private header from ftxui:screen.
"src/ftxui/screen/string_internal.hpp",
"src/ftxui/screen/util.hpp",
# Private header.
"include/ftxui/util/warn_windows_macro.hpp",
],
hdrs = [
"include/ftxui/component/animation.hpp",
@@ -192,6 +184,7 @@ ftxui_cc_library(
"include/ftxui/component/screen_interactive.hpp",
"include/ftxui/component/task.hpp",
],
linkopts = pthread_linkopts(),
deps = [
":dom",
":screen",
@@ -214,6 +207,7 @@ cc_test(
"src/ftxui/component/menu_test.cpp",
"src/ftxui/component/modal_test.cpp",
"src/ftxui/component/radiobox_test.cpp",
"src/ftxui/component/receiver_test.cpp",
"src/ftxui/component/resizable_split_test.cpp",
"src/ftxui/component/slider_test.cpp",
"src/ftxui/component/terminal_input_parser_test.cpp",

View File

@@ -9,29 +9,6 @@ Next
- Use Doxygen awesome. Add our own theme.
- Break the documentation into several pages.
### Build
- Feature: Support C++20 modules.
This requires:
- Using the Ninja or MSVC generator
- A recent Clang/GCC/MSVC compiler.
- Cmake 3.28 or higher.
Usage:
```cpp
import ftxui;
import ftxui.component;
import ftxui.dom;
import ftxui.screen;
import ftxui.util;
```
Thanks @mikomikotaishi for PR #1015.
- Remove dependency on 'pthread'.
### Component
- Fix ScreenInteractive::FixedSize screen stomps on the preceding terminal
output. Thanks @zozowell in #1064.
- Fix vertical `ftxui::Slider`. The "up" key was previously decreasing the
value. Thanks @its-pablo in #1093 for reporting the issue.
6.1.9 (2025-05-07)
------------

View File

@@ -1,19 +1,4 @@
option(FTXUI_BUILD_DOCS "Set to ON to build docs" OFF)
option(FTXUI_BUILD_EXAMPLES "Set to ON to build examples" OFF)
option(FTXUI_BUILD_MODULES "Build the C++20 modules" OFF)
option(FTXUI_BUILD_TESTS "Set to ON to build tests" OFF)
option(FTXUI_BUILD_TESTS_FUZZER "Set to ON to enable fuzzing" OFF)
option(FTXUI_CLANG_TIDY "Execute clang-tidy" OFF)
option(FTXUI_DEV_WARNINGS "Enable more compiler warnings and warnings as errors" OFF)
option(FTXUI_ENABLE_COVERAGE "Execute code coverage" OFF)
option(FTXUI_ENABLE_INSTALL "Generate the install target" ON)
option(FTXUI_QUIET "Set to ON for FTXUI to be quiet" OFF)
if (FTXUI_BUILD_MODULES)
cmake_minimum_required(VERSION 3.28.2)
else()
cmake_minimum_required(VERSION 3.12)
endif()
cmake_minimum_required(VERSION 3.12)
project(ftxui
LANGUAGES CXX
@@ -21,6 +6,15 @@ project(ftxui
DESCRIPTION "C++ Functional Terminal User Interface."
)
option(FTXUI_QUIET "Set to ON for FTXUI to be quiet" OFF)
option(FTXUI_BUILD_EXAMPLES "Set to ON to build examples" OFF)
option(FTXUI_BUILD_DOCS "Set to ON to build docs" OFF)
option(FTXUI_BUILD_TESTS "Set to ON to build tests" OFF)
option(FTXUI_BUILD_TESTS_FUZZER "Set to ON to enable fuzzing" OFF)
option(FTXUI_ENABLE_INSTALL "Generate the install target" ON)
option(FTXUI_CLANG_TIDY "Execute clang-tidy" OFF)
option(FTXUI_ENABLE_COVERAGE "Execute code coverage" OFF)
option(FTXUI_DEV_WARNINGS "Enable more compiler warnings and warnings as errors" OFF)
set(FTXUI_MICROSOFT_TERMINAL_FALLBACK_HELP_TEXT "On windows, assume the \
terminal used will be one of Microsoft and use a set of reasonnable fallback \
@@ -144,20 +138,26 @@ add_library(component
src/ftxui/component/resizable_split.cpp
src/ftxui/component/screen_interactive.cpp
src/ftxui/component/slider.cpp
src/ftxui/component/task.cpp
src/ftxui/component/task_internal.hpp
src/ftxui/component/task_queue.cpp
src/ftxui/component/task_queue.hpp
src/ftxui/component/task_runner.cpp
src/ftxui/component/task_runner.hpp
src/ftxui/component/terminal_input_parser.cpp
src/ftxui/component/terminal_input_parser.hpp
src/ftxui/component/util.cpp
src/ftxui/component/window.cpp
)
target_link_libraries(dom PUBLIC screen)
target_link_libraries(component PUBLIC dom)
target_link_libraries(dom
PUBLIC screen
)
target_link_libraries(component
PUBLIC dom
)
if (NOT EMSCRIPTEN)
find_package(Threads)
target_link_libraries(component
PUBLIC Threads::Threads
)
endif()
include(cmake/ftxui_set_options.cmake)
ftxui_set_options(screen)
@@ -176,13 +176,6 @@ include(cmake/iwyu.cmake)
include(cmake/ftxui_export.cmake)
include(cmake/ftxui_install.cmake)
include(cmake/ftxui_package.cmake)
include(cmake/ftxui_modules.cmake)
add_subdirectory(examples)
add_subdirectory(doc)
# You can generate ./examples_modules/ by running
# ./tools/generate_examples_modules.sh
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples_modules/CMakeLists.txt")
add_subdirectory(examples_modules)
endif()

View File

@@ -1,4 +1,3 @@
<p align="center">
<img src="https://github.com/ArthurSonzogni/FTXUI/assets/4759106/6925b6da-0a7e-49d9-883c-c890e1f36007" alt="Demo image"></img>
<br/>
@@ -19,7 +18,7 @@
<br/>
<a href="https://arthursonzogni.github.io/FTXUI/">Documentation</a> ·
<a href="https://github.com/ArthurSonzogni/FTXUI/issues">Report a Bug</a> ·
<a href="https://arthursonzogni.github.io/FTXUI/examples/">Examples</a> .
<a href="https://arthursonzogni.github.io/FTXUI/examples.html">Examples</a> .
<a href="https://github.com/ArthurSonzogni/FTXUI/issues">Request Feature</a> ·
<a href="https://github.com/ArthurSonzogni/FTXUI/pulls">Send a Pull Request</a>
@@ -40,8 +39,7 @@ A simple cross-platform C++ library for terminal based user interfaces!
* Support for [UTF8](https://en.wikipedia.org/wiki/UTF-8) and [fullwidth chars](https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms) (→ 测试)
* Support for animations. [Demo 1](https://arthursonzogni.github.io/FTXUI/examples/?file=component/menu_underline_animated_gallery), [Demo 2](https://arthursonzogni.github.io/FTXUI/examples/?file=component/button_style)
* Support for drawing. [Demo](https://arthursonzogni.github.io/FTXUI/examples/?file=component/canvas_animated)
* No dependencies.
* [C++20 Module support](https://arthursonzogni.github.io/FTXUI/cpp20-modules.html)
* No dependencies
* **Cross platform**: Linux/MacOS (main target), WebAssembly, Windows (Thanks to contributors!).
* Learn by [examples](#documentation), and [tutorials](#documentation)
* Multiple packages:
@@ -51,9 +49,7 @@ A simple cross-platform C++ library for terminal based user interfaces!
- [Conan](https://conan.io/center/recipes/ftxui) [Debian package](https://tracker.debian.org/pkg/ftxui)
- [Ubuntu package](https://launchpad.net/ubuntu/+source/ftxui)
- [Arch Linux](https://aur.archlinux.org/packages/ftxui/)
- [OpenSUSE](https://build.opensuse.org/package/show/devel:libraries:c_c++/ftxui)
- [XMake](https://xmake.io) repository [package](https://github.com/xmake-io/xmake-repo/blob/dev/packages/f/ftxui/xmake.lua)
- [Nix](https://github.com/ArthurSonzogni/FTXUI/blob/main/flake.nix)
- [OpenSUSE](https://build.opensuse.org/package/show/devel:libraries:c_c++/ftxui)
* Good practices: documentation, tests, fuzzers, performance tests, automated CI, automated packaging, etc...
## Documentation
@@ -99,7 +95,7 @@ Element can be arranged together:
- inside a grid with `gridbox`
- wrap along one direction using the `flexbox`.
Element can become flexible using the `flex` decorator.
Element can become flexible using the the `flex` decorator.
[Example](https://arthursonzogni.github.io/FTXUI/examples_2dom_2vbox_hbox_8cpp-example.html) using `hbox`, `vbox` and `filler`.
@@ -361,10 +357,7 @@ Feel free to add your projects here:
- [terminal-rain](https://github.com/Oakamoore/terminal-rain)
- [keywords](https://github.com/Oakamoore/keywords) ([Play web version :heart:](https://oakamoore.itch.io/keywords))
- [FTB - tertminal file browser](https://github.com/Cyxuan0311/FTB)
- [openJuice](https://github.com/mikomikotaishi/openJuice)
- [SHOOT!](https://github.com/ShingZhanho/ENGG1340-Project-25Spring)
- [VerifySN (Fast Hash Tool)](https://github.com/d06i/verifySN)
- [tic-tac-toe](https://github.com/birland/tic-tac-toe)
### [cpp-best-practices/game_jam](https://github.com/cpp-best-practices/game_jam)
@@ -434,7 +427,6 @@ If you don't, FTXUI may be used from the following packages:
- [Ubuntu package](https://launchpad.net/ubuntu/+source/ftxui),
- [Arch Linux](https://aur.archlinux.org/packages/ftxui/),
- [OpenSUSE](https://build.opensuse.org/package/show/devel:libraries:c_c++/ftxui),
[Nix](https://github.com/ArthurSonzogni/FTXUI/blob/main/flake.nix),
[![Packaging status](https://repology.org/badge/vertical-allrepos/libftxui.svg)](https://repology.org/project/libftxui/versions)
@@ -443,8 +435,6 @@ If you choose to build and link FTXUI yourself, `ftxui-component` must be first
g++ . . . -lftxui-component -lftxui-dom -lftxui-screen . . .
```
To build FTXUI with modules, check [documentation](https://arthursonzogni.github.io/FTXUI/cpp20-modules.html)
## Contributors
<a href="https://github.com/ArthurSonzogni/FTXUI/graphs/contributors">

View File

@@ -43,6 +43,16 @@ def windows_copts():
"//conditions:default": [],
})
def pthread_linkopts():
return select({
# With MSVC, threading is already built-in (you don't need -pthread.
"@rules_cc//cc/compiler:msvc-cl": [],
"@rules_cc//cc/compiler:clang-cl": [],
"@rules_cc//cc/compiler:clang": ["-pthread"],
"@rules_cc//cc/compiler:gcc": ["-pthread"],
"//conditions:default": ["-pthread"],
})
def ftxui_cc_library(
name,
srcs = [],

Submodule build/_deps/googlebenchmark-src deleted from 015d1a091a

View File

@@ -1,42 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
cmake_minimum_required(VERSION 3.31.6)
# Reject any attempt to use a toolchain file. We must not use one because
# we could be downloading it here. If the CMAKE_TOOLCHAIN_FILE environment
# variable is set, the cache variable will have been initialized from it.
unset(CMAKE_TOOLCHAIN_FILE CACHE)
unset(ENV{CMAKE_TOOLCHAIN_FILE})
# We name the project and the target for the ExternalProject_Add() call
# to something that will highlight to the user what we are working on if
# something goes wrong and an error message is produced.
project(googlebenchmark-populate NONE)
# Pass through things we've already detected in the main project to avoid
# paying the cost of redetecting them again in ExternalProject_Add()
set(GIT_EXECUTABLE [==[/usr/bin/git]==])
set(GIT_VERSION_STRING [==[2.51.0]==])
set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
[==[/usr/bin/git;2.51.0]==]
)
include(ExternalProject)
ExternalProject_Add(googlebenchmark-populate
"UPDATE_DISCONNECTED" "False" "GIT_REPOSITORY" "https://github.com/google/benchmark" "EXTERNALPROJECT_INTERNAL_ARGUMENT_SEPARATOR" "GIT_TAG" "015d1a091af6937488242b70121858bce8fd40e9" "GIT_PROGRESS" "TRUE"
SOURCE_DIR "/home/runner/work/FTXUI/FTXUI/build/_deps/googlebenchmark-src"
BINARY_DIR "/home/runner/work/FTXUI/FTXUI/build/_deps/googlebenchmark-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
USES_TERMINAL_DOWNLOAD YES
USES_TERMINAL_UPDATE YES
USES_TERMINAL_PATCH YES
)

Submodule build/_deps/googletest-src deleted from 23ef29555e

View File

@@ -1,42 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
cmake_minimum_required(VERSION 3.31.6)
# Reject any attempt to use a toolchain file. We must not use one because
# we could be downloading it here. If the CMAKE_TOOLCHAIN_FILE environment
# variable is set, the cache variable will have been initialized from it.
unset(CMAKE_TOOLCHAIN_FILE CACHE)
unset(ENV{CMAKE_TOOLCHAIN_FILE})
# We name the project and the target for the ExternalProject_Add() call
# to something that will highlight to the user what we are working on if
# something goes wrong and an error message is produced.
project(googletest-populate NONE)
# Pass through things we've already detected in the main project to avoid
# paying the cost of redetecting them again in ExternalProject_Add()
set(GIT_EXECUTABLE [==[/usr/bin/git]==])
set(GIT_VERSION_STRING [==[2.51.0]==])
set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
[==[/usr/bin/git;2.51.0]==]
)
include(ExternalProject)
ExternalProject_Add(googletest-populate
"UPDATE_DISCONNECTED" "False" "GIT_REPOSITORY" "https://github.com/google/googletest" "EXTERNALPROJECT_INTERNAL_ARGUMENT_SEPARATOR" "GIT_TAG" "23ef29555ef4789f555f1ba8c51b4c52975f0907" "GIT_PROGRESS" "TRUE"
SOURCE_DIR "/home/runner/work/FTXUI/FTXUI/build/_deps/googletest-src"
BINARY_DIR "/home/runner/work/FTXUI/FTXUI/build/_deps/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
USES_TERMINAL_DOWNLOAD YES
USES_TERMINAL_UPDATE YES
USES_TERMINAL_PATCH YES
)

View File

@@ -11,9 +11,6 @@ include(CMakePackageConfigHelpers)
install(
TARGETS screen dom component
EXPORT ftxui-targets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
install(

View File

@@ -5,14 +5,13 @@ function(ftxui_message msg)
endfunction()
ftxui_message("┌─ FTXUI options ─────────────────────")
ftxui_message("│ FTXUI_BUILD_DOCS : ${FTXUI_BUILD_DOCS}")
ftxui_message("│ FTXUI_ENABLE_INSTALL : ${FTXUI_ENABLE_INSTALL}")
ftxui_message("│ FTXUI_BUILD_EXAMPLES : ${FTXUI_BUILD_EXAMPLES}")
ftxui_message("│ FTXUI_BUILD_MODULES : ${FTXUI_BUILD_MODULES}")
ftxui_message("│ FTXUI_QUIET : ${FTXUI_QUIET}")
ftxui_message("│ FTXUI_BUILD_DOCS : ${FTXUI_BUILD_DOCS}")
ftxui_message("│ FTXUI_BUILD_TESTS : ${FTXUI_BUILD_TESTS}")
ftxui_message("│ FTXUI_BUILD_TESTS_FUZZER : ${FTXUI_BUILD_TESTS_FUZZER}")
ftxui_message("│ FTXUI_CLANG_TIDY : ${FTXUI_CLANG_TIDY}")
ftxui_message("│ FTXUI_DEV_WARNINGS : ${FTXUI_DEV_WARNINGS}")
ftxui_message("│ FTXUI_ENABLE_COVERAGE : ${FTXUI_ENABLE_COVERAGE}")
ftxui_message("│ FTXUI_ENABLE_INSTALL : ${FTXUI_ENABLE_INSTALL}")
ftxui_message("│ FTXUI_QUIET : ${FTXUI_QUIET}")
ftxui_message("│ FTXUI_DEV_WARNINGS : ${FTXUI_DEV_WARNINGS}")
ftxui_message("│ FTXUI_CLANG_TIDY : ${FTXUI_CLANG_TIDY}")
ftxui_message("└─────────────────────────────────────")

View File

@@ -1,83 +0,0 @@
if (NOT FTXUI_BUILD_MODULES)
return()
endif()
add_library(ftxui-modules)
target_sources(ftxui-modules
PUBLIC FILE_SET CXX_MODULES FILES
src/ftxui/ftxui.cppm
src/ftxui/component.cppm
src/ftxui/component/animation.cppm
src/ftxui/component/captured_mouse.cppm
src/ftxui/component/component.cppm
src/ftxui/component/component_base.cppm
src/ftxui/component/component_options.cppm
src/ftxui/component/event.cppm
src/ftxui/component/loop.cppm
src/ftxui/component/mouse.cppm
src/ftxui/component/receiver.cppm
src/ftxui/component/screen_interactive.cppm
src/ftxui/component/task.cppm
src/ftxui/dom.cppm
src/ftxui/dom/canvas.cppm
src/ftxui/dom/deprecated.cppm
src/ftxui/dom/direction.cppm
src/ftxui/dom/elements.cppm
src/ftxui/dom/flexbox_config.cppm
src/ftxui/dom/linear_gradient.cppm
src/ftxui/dom/node.cppm
src/ftxui/dom/requirement.cppm
src/ftxui/dom/selection.cppm
src/ftxui/dom/table.cppm
src/ftxui/screen.cppm
src/ftxui/screen/box.cppm
src/ftxui/screen/color.cppm
src/ftxui/screen/color_info.cppm
src/ftxui/screen/deprecated.cppm
src/ftxui/screen/image.cppm
src/ftxui/screen/pixel.cppm
src/ftxui/screen/screen.cppm
src/ftxui/screen/string.cppm
src/ftxui/screen/terminal.cppm
src/ftxui/util.cppm
src/ftxui/util/autoreset.cppm
src/ftxui/util/ref.cppm
)
target_link_libraries(ftxui-modules
PUBLIC
ftxui::screen
ftxui::dom
ftxui::component
)
target_compile_features(ftxui-modules PUBLIC cxx_std_20)
# TODO: Explain why this is needed.
if (CMAKE_COMPILER_IS_GNUCXX)
target_compile_options(ftxui-modules PUBLIC -fmodules-ts)
endif ()
add_library(ftxui::modules ALIAS ftxui-modules)
if(FTXUI_ENABLE_INSTALL)
include(GNUInstallDirs)
install(TARGETS ftxui-modules
EXPORT ftxui-targets
FILE_SET CXX_MODULES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ftxui
FILE_SET HEADERS
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ftxui
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ftxui
)
install(EXPORT ftxui-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ftxui
CXX_MODULES_DIRECTORY ${CMAKE_INSTALL_LIBDIR}/cmake/ftxui
)
install(FILES my_package-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ftxui
)
endif()

View File

@@ -101,5 +101,6 @@ endfunction()
if (EMSCRIPTEN)
string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -s ASYNCIFY")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -s PROXY_TO_PTHREAD")
endif()

View File

@@ -19,10 +19,11 @@ add_executable(ftxui-tests
src/ftxui/component/menu_test.cpp
src/ftxui/component/modal_test.cpp
src/ftxui/component/radiobox_test.cpp
src/ftxui/util/ref_test.cpp
src/ftxui/component/receiver_test.cpp
src/ftxui/component/resizable_split_test.cpp
src/ftxui/component/screen_interactive_test.cpp
src/ftxui/component/slider_test.cpp
src/ftxui/component/task_test.cpp
src/ftxui/component/terminal_input_parser_test.cpp
src/ftxui/component/toggle_test.cpp
src/ftxui/dom/blink_test.cpp
@@ -50,7 +51,6 @@ add_executable(ftxui-tests
src/ftxui/dom/vbox_test.cpp
src/ftxui/screen/color_test.cpp
src/ftxui/screen/string_test.cpp
src/ftxui/util/ref_test.cpp
)
target_link_libraries(ftxui-tests

View File

@@ -1001,12 +1001,48 @@ INPUT_FILE_ENCODING =
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.cppm \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f \
*.for \
*.tcl \
*.vhd \
*.vhdl \
*.ucf \
*.qsf
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.

View File

@@ -1,107 +0,0 @@
@page cpp20-modules C++20 Modules
> [!WARNING]
> This feature is still in development, and the API may change in future releases.
> Your contribution is needed to help us improve the compatibility and usability
> of C++20 modules in FTXUI. If you encounter any issues or have suggestions,
> please open an issue.
FTXUI experimentally supports
[C++20 modules](https://en.cppreference.com/w/cpp/language/modules) to reduce
compilation times and improve code organization. Each header has a
corresponding module.
Use the FTXUI_BUILD_MODULES option to build the FTXUI project itself to provide C++ 20 modules,
for example with CMake and Ninja:
```sh
cmake \
-DCMAKE_GENERATOR=Ninja \
-DFTXUI_BUILD_MODULES=ON \
..
ninja
```
> [!NOTE]
> To use modules, you need a C++20 compatible compiler, CMake version 3.20 or
> higher, and use a compatible generator like Ninja. Note that Makefile
> generators **do not support modules**.
Then, in your own code you can consume the modules and code as normal:
```cpp
import ftxui;
int main() {
auto screen = ftxui::ScreenInteractive::TerminalOutput();
auto button = ftxui::Button("Click me", screen.QuitClosure());
screen.Loop(button);
return 0;
}
```
Note, the `ftxui` convenience module which simply pulls together all the modules:
```cpp
export import ftxui.component;
export import ftxui.dom;
export import ftxui.screen;
export import ftxui.util;
```
You can instead import only the module(s) you need if desired.
To properly find and link the modules with CMake, use `target_link_libraries` to get the right
compiler, linker, etc. flags.
```cmake
target_link_libraries(my_executable
#...whatever...
PRIVATE ftxui::modules
)
```
### Module list
The modules directly reference the corresponding header, or a group of related
headers to provide a more convenient interface. The following modules
are available:
- `ftxui`
- `ftxui.component`
- `ftxui.component.Animation`
- `ftxui.component.CapturedMouse`
- `ftxui.component.Component`
- `ftxui.component.ComponentBase`
- `ftxui.component.ComponentOptions`
- `ftxui.component.Event`
- `ftxui.component.Loop`
- `ftxui.component.Mouse`
- `ftxui.component.Receiver`
- `ftxui.component.ScreenInteractive`
- `ftxui.component.Task`
- `ftxui.dom`
- `ftxui.dom.Canvas`
- `ftxui.dom.Deprecated`
- `ftxui.dom.Direction`
- `ftxui.dom.Elements`
- `ftxui.dom.FlexboxConfig`
- `ftxui.dom.LinearGradient`
- `ftxui.dom.Node`
- `ftxui.dom.Requirement`
- `ftxui.dom.Selection`
- `ftxui.dom.Table`
- `ftxui.screen`
- `ftxui.screen.Box`
- `ftxui.screen.Color`
- `ftxui.screen.ColorInfo`
- `ftxui.screen.Deprecated`
- `ftxui.screen.Image`
- `ftxui.screen.Pixel`
- `ftxui.screen.Screen`
- `ftxui.screen.String`
- `ftxui.screen.Terminal`
- `ftxui.util`
- `ftxui.util.AutoReset`
- `ftxui.util.Ref`

View File

@@ -91,39 +91,6 @@
}
</script>
<script type="module">
// Click on the navtree, except for the main page where this is already done
// automatically.
let delay = 0;
while(true) {
const navtree = document.querySelector("div.item.selected");
if (!navtree) {
delay *= 2;
delay += 1;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
// Include only selected navtree items.
console.log("navtree.textContent", navtree.textContent);
if (!navtree.textContent.includes("Getting Started") &&
!navtree.textContent.includes("Installation") &&
!navtree.textContent.includes("ftxui / screen") &&
!navtree.textContent.includes("ftxui / dom") &&
!navtree.textContent.includes("ftxui / component") &&
!navtree.textContent.includes("Reference")) {
break;
}
// Find the first link inside the navtree.
const link = navtree.querySelector("a");
if (link) {
// Simulate a click on the link.
link.click();
break;
}
}
</script>
$treeview
$search

View File

@@ -16,11 +16,6 @@ This page serves as an entry point for the available integration methods.
- @subpage installation_vcpkg
- @subpage installation_conan
- @subpage installation_manual
- @subpage installation_nix
- @subpage installation_debian
- @subpage installation_arch
- @subpage installation_opensuse
- @subpage installation_xmake
## Next Steps

View File

@@ -1,34 +0,0 @@
@page installation_arch Arch Linux
FTXUI is packaged on the AUR. Install using an AUR helper:
```bash
yay -S ftxui
```
You can also manually download the PKGBUILD from <https://aur.archlinux.org/packages/ftxui>.
Once installed, you can use it in your CMake projects by adding the following to your `CMakeLists.txt`:
```cmake
find_package(ftxui REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main
PRIVATE ftxui::screen
PRIVATE ftxui::dom
PRIVATE ftxui::component
)
```
> [!note]
> This is an unofficial package. That means it is not maintained by the FTXUI
> team, but by the community. The package maintainers seems to actively update
> the package to the latest version. Thanks to the maintainers for their work!
<div class="section_buttons">
| Previous |
|:------------------|
| [Getting Started](getting-started.html) |
</div>

View File

@@ -10,7 +10,7 @@ This page explains how to depend on FTXUI using [CMake](https://cmake.org).
This approach downloads FTXUI at configure time and doesn't require a system-wide install.
```cmake
```fortran
include(FetchContent)
FetchContent_Declare(ftxui
@@ -34,8 +34,8 @@ This ensures reproducible builds and easy dependency management.
If FTXUI is installed system-wide or via a package manager (e.g. vcpkg or Conan), you can use:
```cmake
find_package(ftxui REQUIRED)
```fortran
fortranind_package(ftxui REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main
@@ -51,7 +51,7 @@ Make sure the package is visible in your `CMAKE_PREFIX_PATH`.
You can also add FTXUI as a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules), keeping it as part of your repository:
```cmake
```fortran
git submodule add https://github.com/ArthurSonzogni/FTXUI external/ftxui
git submodule update --init --recursive
```
@@ -66,7 +66,7 @@ git submodule update --init --recursive
Then in your `CMakeLists.txt`:
```cmake
```fortran
add_subdirectory(external/ftxui)
add_executable(main main.cpp)

View File

@@ -1,104 +1,20 @@
@page installation_conan Conan
@tableofcontents
FTXUI can be easily obtained and integrated into your project using the Conan package manager.
## Conan Package
## Prerequisites
Unofficial support for FTXUI exists on Conan Center:
First, ensure that Conan is installed on your system. If not, you can install it via pip:
- https://conan.io/center/recipes/ftxui
```powershell
pip install conan
```
Conan often works in tandem with CMake, so you will need to have CMake installed as well. Once you have confirmed both Conan and CMake are installed, create a project directory, for example, `ftxui-demo`:
## TODO
```powershell
mkdir C:\ftxui-demo
cd C:\ftxui-demo
```
## Configuration
After ensuring your environment is set up correctly, create a Conan configuration file `conanfile.txt`. This file is used to declare your project's dependencies. The community-maintained package for FTXUI can be found on [Conan Center](https://conan.io/center/recipes/ftxui).
> [!note]
> This is an unofficial build script. This means it is not maintained by the FTXUI
> team but by the community. The package maintainer appears to actively update it
> to the latest releases. Many thanks to the maintainer for their work!
@todo If you are familiar with the process, please consider adding an "official" build script to Conan Center.
This could be a GitHub Action that automatically updates Conan Center upon new releases.
```ini
[requires]
ftxui/6.0.2
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout
```
## Install Dependencies and Build
Once configured, run the following command to install FTXUI and its dependencies:
```powershell
conan install . --output-folder=build --build=missing
```
This will download and install `ftxui/6.0.2` along with all its dependencies from Conan's remote repositories.
After the installation completes, you can test it by creating a `demo.cpp` file in your project directory:
```cpp
#include <ftxui/screen/screen.hpp>
#include <ftxui/dom/elements.hpp>
#include <iostream>
int main() {
using namespace ftxui;
auto document = hbox({
text(" Hello "),
text("FTXUI ") | bold | color(Color::Red),
text(" world! ")
});
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document);
std::cout << screen.ToString() << std::endl;
return 0;
}
```
If the test is successful, you can then create a `CMakeLists.txt` file in the project directory:
```cmake
cmake_minimum_required(VERSION 3.20)
project(ftxui-demo)
# Set the C++ standard
set(CMAKE_CXX_STANDARD 20)
# Find the FTXUI package installed via Conan
find_package(ftxui CONFIG REQUIRED)
# Create the executable
add_executable(demo demo.cpp)
# Link the executable to the FTXUI library
target_link_libraries(demo PRIVATE ftxui::component)
```
@todo 考虑到中国多数地区使用Conan很有可能遇到各种网络问题我想做一个定制的版本说明但是我对conan的了解有限再加上没有找到合适的资料因此这个计划短暂的被搁置了如果您知道方法欢迎在[中文版本](xiaoditx.girhub.io/public/docs/ftxui%E4%B8%AD%E6%96%87%E7%BF%BB%E8%AF%91/installation/conan/)的下方留下评论以提醒我
---
This page is incomplete. If you use FTXUI with Conan and can provide a minimal working setup, feel free to contribute.
<div class="section_buttons">
| Previous |
|:------------------|
| [Getting Started](getting-started.html) |
</div>
</div>

View File

@@ -1,42 +0,0 @@
@page installation_debian Debian/Ubuntu
## Debian and Ubuntu Packages (Unofficial)
Pre-built packages are provided by the distributions. Install with:
```bash
sudo apt install libftxui-dev
```
The following packages are available:
- `ftxui-doc`
- `ftxui-examples`
- `libftxui-component<version>`
- `libftxui-dev`
- `libftxui-dom<version>`
- `libftxui-screen<version>`
Once installed, you can use it in your CMake projects by adding the following to
your `CMakeLists.txt`:
```cmake
find_package(ftxui REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main
PRIVATE ftxui::screen
PRIVATE ftxui::dom
PRIVATE ftxui::component
)
```
> [!note]
> This is an **unofficial** package. That means it is not maintained by the FTXUI
> team, but by the community.
<div class="section_buttons">
| Previous |
|:------------------|
| [Getting Started](getting-started.html) |
</div>

View File

@@ -1,35 +0,0 @@
@page installation_manual Manual
@tableofcontents
## Building from Source (Official)
Clone and build the project using CMake:
```bash
git clone https://github.com/ArthurSonzogni/FTXUI.git
cd FTXUI
cmake -S . -B build -DFTXUI_ENABLE_INSTALL=ON -D
cmake --build build -j
sudo cmake --install build
```
Once installed you can use it in your CMake projects by adding the following to your `CMakeLists.txt`:
```cmake
find_package(ftxui REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main
PRIVATE ftxui::screen
PRIVATE ftxui::dom
PRIVATE ftxui::component
)
```
<div class="section_buttons">
| Previous |
|:------------------|
| [Getting Started](getting-started.html) |
</div>

View File

@@ -1,38 +0,0 @@
@page installation_nix Nix
> [!note]
> FTXUI author is not very knowledgeable about Nix. This page has been mostly
> generated by AI. If you have any suggestions to improve it, please open a
> PR.
## Nix Flake
FTXUI ships with a `flake.nix` providing both packages and a development shell.
### Build the Library
```bash
nix build github:ArthurSonzogni/FTXUI
```
The resulting package is accessible via the `result` link.
### Use as a Dependency
Add FTXUI to your flake inputs:
```nix
{
inputs.ftxui.url = "github:ArthurSonzogni/FTXUI";
}
```
Then reference `ftxui.packages.<system>.ftxui` in your outputs.
<div class="section_buttons">
| Previous |
|:------------------|
| [Getting Started](getting-started.html) |
</div>

View File

@@ -1,32 +0,0 @@
@page installation_opensuse openSUSE
## openSUSE Package (Unofficial)
FTXUI seems to be available from the `devel:libraries:c_c++` repository.
```bash
sudo zypper addrepo https://download.opensuse.org/repositories/devel:libraries:c_c++/openSUSE_Leap_$releasever/devel:libraries:c_c++.repo
sudo zypper install ftxui
```
See <https://build.opensuse.org/package/show/devel:libraries:c_c++/ftxui> for details.
> [!note]
> This is an **unofficial** package. That means it is not maintained by the FTXUI
> team, but by the community.
--
> [!note]
> The FTXUI author is not very knowledgeable about openSUSE. This page has been
> mostly generated by AI. If you have any suggestions to improve it, please open
> a PR.
<div class="section_buttons">
| Previous |
|:------------------|
| [Getting Started](getting-started.html) |
</div>

View File

@@ -1,74 +1,15 @@
@page installation_vcpkg Vcpkg
@tableofcontents
# Vcpkg Package
## Vcpkg Package
FTXUI is available in the [Vcpkg registry](https://vcpkg.link/ports/ftxui)
To use it, you can add the following to your `vcpkg.json`:
```json
{
"name": "your-project",
"version-string": "0.1.0",
"dependencies": [
{
"name": "ftxui",
"version>=": "6.1.9"
}
]
}
```
# Install FTXUI using Vcpkg
```bash
vcpkg install --triplet x64-linux # or x64-windows / arm64-osx etc.
```
# Configure your build system.
If you are using CMake, you can use the following in your `CMakeLists.txt`:
**CMakeLists.txt**
```cmake
cmake_minimum_required(VERSION 3.15)
project(my_project)
# Make sure vcpkg toolchain file is passed at configure time
find_package(ftxui CONFIG REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main
PRIVATE ftxui::screen
PRIVATE ftxui::dom
PRIVATE ftxui::component
)
```
**main.cpp**
```cpp
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/component/component.hpp>
#include <ftxui/component/component_options.hpp>
int main() {
using namespace ftxui;
auto screen = ScreenInteractive::TerminalOutput();
auto button = Button("Click me", [] { std::cout << "Clicked!\n"; });
screen.Loop(button);
}
```
**Configure and build the project**
```bash
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build build
./build/main
```
FTXUI is available in the Vcpkg registry:
- https://vcpkg.link/ports/ftxui
## TODO
This page is incomplete. If you use FTXUI with Vcpkg, please help improve this page by contributing working configuration examples.
<div class="section_buttons">

View File

@@ -1,40 +0,0 @@
@page installation_xmake XMake
@tableofcontents
## XMake Package (Unofficial)
FTXUI is available in the [xmake-repo](https://github.com/xmake-io/xmake-repo/blob/dev/packages/f/ftxui/xmake.lua)
Example `xmake.lua` snippet:
```lua
add_requires("ftxui", {system = false})
target("demo")
set_kind("binary")
add_files("src/*.cpp")
add_packages("ftxui")
```
Refer to the [XMake documentation](https://xmake.io) for further options.
> [!note]
> This is an **unofficial** package. That means it is not maintained by the FTXUI
> team, but by the community.
---
> [!note]
> The FTXUI author is not very knowledgeable about openSUSE. This page has been
> mostly generated by AI. If you have any suggestions to improve it, please open
> a PR.
---
<div class="section_buttons">
| Previous |
|:------------------|
| [Getting Started](getting-started.html) |
</div>

View File

@@ -14,7 +14,7 @@ A `ftxui::Component` is a shared pointer to a `ftxui::ComponentBase`. The latter
- `ftxui::ComponentBase::Render()`: How to render the interface.
- `ftxui::ComponentBase::OnEvent()`: How to react to events.
- `ftxui::ComponentBase::Add()`: Construct a parent/child relationship
between two components. The tree of components is used to define how to
between two components. The tree of component is used to define how to
navigate using the keyboard.
`ftxui::Element` are used to render a single frame.
@@ -45,7 +45,7 @@ Produced by: `ftxui::Input()` from "ftxui/component/component.hpp"
## Filtered input
One can filter out the characters received by the input component, using
On can filter out the characters received by the input component, using
`ftxui::CatchEvent`.
```cpp
@@ -123,8 +123,8 @@ Produced by: `ftxui::Radiobox()` from "ftxui/component/component.hpp"
# Dropdown {#component-dropdown}
A drop-down menu is a component that, when opened, displays a list of elements
for the user to select from.
A drop down menu is a component that when checked display a list of element for
the user to select one.
[Example](https://arthursonzogni.github.io/FTXUI/examples_2component_2dropdown_8cpp-example.html):
@@ -204,12 +204,12 @@ component = component
# Collapsible {#component-collapsible}
Useful for visual elements whose visibility can be toggled on or off by the
user. Essentially, this is the combination of the `ftxui::Checkbox()` and
Useful for visual elements whose visibility can be toggle on/off by the user.
Essentially, this the combination of the `ftxui::Checkbox()` and
`ftxui::Maybe()` components.
```cpp
auto collapsible = Collapsible("Show more", inner_element);
auto collabsible = Collapsible("Show more", inner_element);
```
# Maybe {#component-maybe}
@@ -245,7 +245,7 @@ component = component
Produced by: `ftxui::Container::Horizontal()` from
"ftxui/component/component.hpp". It displays a list of components horizontally
and handles keyboard/mouse navigation.
and handle keyboard/mouse navigation.
## Vertical {#component-vertical}
@@ -256,8 +256,8 @@ and handles keyboard/mouse navigation.
## Tab {#component-tab}
Produced by: `ftxui::Container::Tab()` from
"ftxui/component/component.hpp". It takes a list of components and displays
only one of them. This is useful for implementing a tab bar.
"ftxui/component/component.hpp". It take a list of component and display only
one of them. This is useful for implementing a tab bar.
[Vertical](https://arthursonzogni.github.io/FTXUI/examples_2component_2tab_vertical_8cpp-example.html):

View File

@@ -207,7 +207,7 @@ Code:
border(gauge(0.5))
```
Terminal output:
Teminal output:
```bash
┌────────────────────────────────────────────────────────────────────────────┐
│██████████████████████████████████████ │
@@ -407,7 +407,7 @@ Checkout this
and the associated
[demo](https://arthursonzogni.github.io/FTXUI/examples/?file=component/flexbox).
Element can also become flexible using the `ftxui::flex` decorator.
Element can also become flexible using the the `ftxui::flex` decorator.
Code:
```cpp

View File

@@ -1,4 +1,4 @@
# ftxui {#ftxui}
# Modules {#modules}
![title-img](https://nsm09.casimages.com/img/2025/05/30//2505300816063242518595251.jpg)

View File

@@ -15,14 +15,16 @@ add_subdirectory(component)
add_subdirectory(dom)
if (EMSCRIPTEN)
string(APPEND CMAKE_EXE_LINKER_FLAGS " -s ALLOW_MEMORY_GROWTH=1")
target_link_options(component PUBLIC "SHELL: -s ALLOW_MEMORY_GROWTH=1")
get_property(EXAMPLES GLOBAL PROPERTY FTXUI::EXAMPLES)
foreach(file
"index.css"
"index.html"
"index.mjs"
"run_webassembly.py"
"index.css"
"sw.js"
)
"run_webassembly.py")
configure_file(${file} ${file})
endforeach(file)
endif()

View File

@@ -1,64 +1,9 @@
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
#include <memory> // for shared_ptr, __shared_ptr_access
#include <string> // for operator+, to_string
#include "ftxui/component/component.hpp"
#include "ftxui/component/screen_interactive.hpp"
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, gauge, text, Element, operator|, vbox, border
using namespace ftxui;
// This is a helper function to create a button with a custom style.
// The style is defined by a lambda function that takes an EntryState and
// returns an Element.
// We are using `center` to center the text inside the button, then `border` to
// add a border around the button, and finally `flex` to make the button fill
// the available space.
ButtonOption Style() {
auto option = ButtonOption::Animated();
option.transform = [](const EntryState& s) {
auto element = text(s.label);
if (s.focused) {
element |= bold;
}
return element | center | borderEmpty | flex;
};
return option;
}
int main() {
int value = 50;
// clang-format off
auto btn_dec_01 = Button("-1", [&] { value -= 1; }, Style());
auto btn_inc_01 = Button("+1", [&] { value += 1; }, Style());
auto btn_dec_10 = Button("-10", [&] { value -= 10; }, Style());
auto btn_inc_10 = Button("+10", [&] { value += 10; }, Style());
// clang-format on
// The tree of components. This defines how to navigate using the keyboard.
// The selected `row` is shared to get a grid layout.
int row = 0;
auto buttons = Container::Vertical({
Container::Horizontal({btn_dec_01, btn_inc_01}, &row) | flex,
Container::Horizontal({btn_dec_10, btn_inc_10}, &row) | flex,
});
// Modify the way to render them on screen:
auto component = Renderer(buttons, [&] {
return vbox({
text("value = " + std::to_string(value)),
separator(),
buttons->Render() | flex,
}) |
flex | border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(component);
return 0;
int main(){
auto screen = ftxui::ScreenInteractive::Fullscreen();
auto testComponent = ftxui::Renderer([](){return ftxui::text("test Component");});
screen.Loop(testComponent);
return 0;
}

View File

@@ -133,9 +133,8 @@ int main() {
float dy = 50.f;
ys[x] = int(dy + 20 * cos(dx * 0.14) + 10 * sin(dx * 0.42));
}
for (int x = 1; x < 99; x++) {
for (int x = 1; x < 99; x++)
c.DrawPointLine(x, ys[x], x + 1, ys[x + 1]);
}
return canvas(std::move(c));
});

View File

@@ -82,12 +82,10 @@ int main() {
size(WIDTH, EQUAL, dimx) | size(HEIGHT, EQUAL, dimy) |
bgcolor(Color::HSV(index * 25, 255, 255)) |
color(Color::Black);
if (element_xflex_grow) {
if (element_xflex_grow)
element = element | xflex_grow;
}
if (element_yflex_grow) {
if (element_yflex_grow)
element = element | yflex_grow;
}
return element;
};
@@ -121,12 +119,10 @@ int main() {
group = group | notflex;
if (!group_xflex_grow) {
if (!group_xflex_grow)
group = hbox(group, filler());
}
if (!group_yflex_grow) {
if (!group_yflex_grow)
group = vbox(group, filler());
}
group = group | flex;
return group;

View File

@@ -1,12 +1,11 @@
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
#include <stddef.h> // for size_t
#include <array> // for array
#include <atomic> // for atomic
#include <chrono> // for operator""s, chrono_literals
#include <cmath> // for sin
#include <ftxui/component/loop.hpp>
#include <stddef.h> // for size_t
#include <array> // for array
#include <atomic> // for atomic
#include <chrono> // for operator""s, chrono_literals
#include <cmath> // for sin
#include <functional> // for ref, reference_wrapper, function
#include <memory> // for allocator, shared_ptr, __shared_ptr_access
#include <string> // for string, basic_string, char_traits, operator+, to_string
@@ -270,7 +269,7 @@ int main() {
auto spinner_tab_renderer = Renderer([&] {
Elements entries;
for (int i = 0; i < 22; ++i) {
entries.push_back(spinner(i, shift / 5) | bold |
entries.push_back(spinner(i, shift / 2) | bold |
size(WIDTH, GREATER_THAN, 2) | border);
}
return hflow(std::move(entries));
@@ -513,20 +512,24 @@ int main() {
});
});
Loop loop(&screen, main_renderer);
while (!loop.HasQuitted()) {
// Update the state of the application.
shift++;
std::atomic<bool> refresh_ui_continue = true;
std::thread refresh_ui([&] {
while (refresh_ui_continue) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(0.05s);
// The |shift| variable belong to the main thread. `screen.Post(task)`
// will execute the update on the thread where |screen| lives (e.g. the
// main thread). Using `screen.Post(task)` is threadsafe.
screen.Post([&] { shift++; });
// After updating the state, request a new frame to be drawn. This is done
// by simulating a new "custom" event to be handled.
screen.Post(Event::Custom);
}
});
// Request a new frame to be drawn.
screen.RequestAnimationFrame();
// Execute events, and draw the next frame.
loop.RunOnce();
// Sleep for a short duration to control the frame rate (60 FPS).
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 60));
}
screen.Loop(main_renderer);
refresh_ui_continue = false;
refresh_ui.join();
return 0;
}

View File

@@ -22,12 +22,10 @@ MenuEntryOption Colored(ftxui::Color c) {
option.transform = [c](EntryState state) {
state.label = (state.active ? "> " : " ") + state.label;
Element e = text(state.label) | color(c);
if (state.focused) {
if (state.focused)
e = e | inverted;
}
if (state.active) {
if (state.active)
e = e | bold;
}
return e;
};
return option;

View File

@@ -17,9 +17,8 @@ int main() {
std::vector<std::string> entries;
int selected = 0;
for (int i = 0; i < 30; ++i) {
for (int i = 0; i < 30; ++i)
entries.push_back("Entry " + std::to_string(i));
}
auto radiobox = Menu(&entries, &selected);
auto renderer = Renderer(radiobox, [&] {
return radiobox->Render() | vscroll_indicator | frame |

View File

@@ -17,9 +17,8 @@ int main() {
std::vector<std::string> entries;
int selected = 0;
for (int i = 0; i < 100; ++i) {
for (int i = 0; i < 100; ++i)
entries.push_back(std::to_string(i));
}
auto radiobox = Menu(&entries, &selected, MenuOption::Horizontal());
auto renderer = Renderer(
radiobox, [&] { return radiobox->Render() | hscroll_indicator | frame; });

View File

@@ -116,12 +116,10 @@ Component VMenu1(std::vector<std::string>* entries, int* selected) {
option.entries_option.transform = [](EntryState state) {
state.label = (state.active ? "> " : " ") + state.label;
Element e = text(state.label);
if (state.focused) {
if (state.focused)
e = e | bgcolor(Color::Blue);
}
if (state.active) {
if (state.active)
e = e | bold;
}
return e;
};
return Menu(entries, selected, option);
@@ -132,12 +130,10 @@ Component VMenu2(std::vector<std::string>* entries, int* selected) {
option.entries_option.transform = [](EntryState state) {
state.label += (state.active ? " <" : " ");
Element e = hbox(filler(), text(state.label));
if (state.focused) {
if (state.focused)
e = e | bgcolor(Color::Red);
}
if (state.active) {
if (state.active)
e = e | bold;
}
return e;
};
return Menu(entries, selected, option);
@@ -148,16 +144,13 @@ Component VMenu3(std::vector<std::string>* entries, int* selected) {
option.entries_option.transform = [](EntryState state) {
Element e = state.active ? text("[" + state.label + "]")
: text(" " + state.label + " ");
if (state.focused) {
if (state.focused)
e = e | bold;
}
if (state.focused) {
if (state.focused)
e = e | color(Color::Blue);
}
if (state.active) {
if (state.active)
e = e | bold;
}
return e;
};
return Menu(entries, selected, option);
@@ -252,12 +245,10 @@ Component HMenu5(std::vector<std::string>* entries, int* selected) {
animation::easing::ElasticOut);
option.entries_option.transform = [](EntryState state) {
Element e = text(state.label) | hcenter | flex;
if (state.active && state.focused) {
if (state.active && state.focused)
e = e | bold;
}
if (!state.focused && !state.active) {
if (!state.focused && !state.active)
e = e | dim;
}
return e;
};
option.underline.color_inactive = Color::Default;

View File

@@ -20,9 +20,8 @@ using namespace ftxui;
Component DummyComponent(int id) {
return Renderer([id](bool focused) {
auto t = text("component " + std::to_string(id));
if (focused) {
if (focused)
t = t | inverted;
}
return t;
});
}

View File

@@ -17,9 +17,8 @@ int main() {
std::vector<std::string> entries;
int selected = 0;
for (int i = 0; i < 30; ++i) {
for (int i = 0; i < 30; ++i)
entries.push_back("RadioBox " + std::to_string(i));
}
auto radiobox = Radiobox(&entries, &selected);
auto renderer = Renderer(radiobox, [&] {
return radiobox->Render() | vscroll_indicator | frame |

View File

@@ -19,11 +19,10 @@ int main() {
// 1. Example of focusable renderer:
auto renderer_focusable = Renderer([](bool focused) {
if (focused) {
if (focused)
return text("FOCUSABLE RENDERER()") | center | bold | border;
} else {
else
return text(" Focusable renderer() ") | center | border;
}
});
// 2. Examples of a non focusable renderer.
@@ -34,11 +33,10 @@ int main() {
// 3. Renderer can wrap other components to redefine their Render() function.
auto button = Button("Wrapped quit button", screen.ExitLoopClosure());
auto renderer_wrap = Renderer(button, [&] {
if (button->Focused()) {
if (button->Focused())
return button->Render() | bold | color(Color::Red);
} else {
else
return button->Render();
}
});
// Let's renderer everyone:

View File

@@ -3,7 +3,6 @@
// the LICENSE file.
#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <string>
using namespace ftxui;

View File

@@ -3,7 +3,6 @@
// the LICENSE file.
#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <string>
using namespace ftxui;

View File

@@ -32,12 +32,10 @@ int main() {
// Plot a function:
std::vector<int> ys(100);
for (int x = 0; x < 100; x++) {
for (int x = 0; x < 100; x++)
ys[x] = int(80 + 20 * cos(x * 0.2));
}
for (int x = 0; x < 99; x++) {
for (int x = 0; x < 99; x++)
c.DrawPointLine(x, ys[x], x + 1, ys[x + 1], Color::Red);
}
auto document = canvas(&c) | border;

View File

@@ -86,9 +86,8 @@ int main() {
auto render = [&]() {
std::vector<Element> entries;
for (auto& task : displayed_task) {
for (auto& task : displayed_task)
entries.push_back(renderTask(task));
}
return vbox({
// List of tasks.
@@ -139,9 +138,8 @@ int main() {
std::this_thread::sleep_for(0.01s);
// Exit
if (nb_active + nb_queued == 0) {
if (nb_active + nb_queued == 0)
break;
}
// Update the model for the next frame.
updateModel();

View File

@@ -21,9 +21,8 @@ int main() {
for (int index = 0; index < 200; ++index) {
std::vector<Element> entries;
for (int i = 0; i < 23; ++i) {
if (i != 0) {
if (i != 0)
entries.push_back(separator());
}
entries.push_back( //
hbox({
text(std::to_string(i)) | size(WIDTH, EQUAL, 2),

View File

@@ -1,19 +1,15 @@
@import url(https://fonts.googleapis.com/css?family=Khula:700);
html {
--toc-width: 250px;
}
body {
background-color: #EEE;
padding: 0px;
margin: 0px;
background-color:#EEE;
padding:0px;
margin:0px;
font-family: Khula, Helvetica, sans-serif;
font-size: 130%;
}
.page {
max-width: 1300px;
max-width:1300px;
margin: auto;
padding: 10px;
}
@@ -24,7 +20,7 @@ a {
margin: 0 -.25rem;
padding: 0 .25rem;
transition: color .3s ease-in-out,
box-shadow .3s ease-in-out;
box-shadow .3s ease-in-out;
}
a:hover {
@@ -34,48 +30,45 @@ a:hover {
h1 {
text-decoration: underline;
width: 100%;
background-color: rgba(100, 100, 255, 0.5);
width:100%;
background-color: rgba(100,100,255,0.5);
padding: 10px;
margin: 0;
}
#selectExample {
flex: 1;
flex:1;
}
#selectExample,
#selectExample option {
#selectExample, #selectExample option {
font-size: 16px;
font-family: sans-serif;
font-weight: 700;
line-height: 1.3;
border: 0px;
border:0px;
background-color: #bbb;
color: black;
color:black;
}
#selectExample:focus {
outline: none;
outline:none;
}
#terminal {
width: 100%;
width:100%;
height 500px;
height: calc(clamp(200px, 100vh - 300px, 900px));
overflow: hidden;
border: none;
padding: 10px;
margin: 10px;
border:none;
background-color:black;
}
#terminalContainer {
overflow: hidden;
border-radius: 10px;
box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.75),
0px 2px 80px 0px rgba(0, 0, 0, 0.50);
background-color: black;
box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.75),
0px 2px 80px 0px rgba(0,0,0,0.50);
}
.fakeButtons {
@@ -83,7 +76,7 @@ h1 {
width: 10px;
border-radius: 50%;
border: 1px solid #000;
margin: 6px;
margin:6px;
background-color: #ff3b47;
border-color: #9d252b;
display: inline-block;
@@ -102,79 +95,13 @@ h1 {
}
.fakeMenu {
display: flex;
display:flex;
flex-direction: row;
width: 100%;
width:100%;
box-sizing: border-box;
height: 25px;
background-color: #bbb;
color: black;
color:black;
margin: 0 auto;
overflow: hidden;
}
.toc-container {
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: var(--toc-width);
background: white;
padding: 0;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
}
.toc-title {
font-weight: bold;
margin-bottom: 5px;
font-size: 0.9em;
color: #555;
position: sticky;
transition: position 1.0s ease-in-out;
top: 0;
z-index: 1;
padding: 20px;
margin: 0;
border-bottom: 1px solid #ddd;
/* Gradient background for the title */
background-color: #f0f0f0;
}
.toc-item {
padding: 3px 8px;
margin: 0;
cursor: pointer;
font-size: 0.85em;
border-radius: 3px;
transition: background 0.2s;
}
.toc-item:hover {
background: #f0f0f0;
}
.toc-item.selected {
background: #e0e0e0;
font-weight: bold;
}
@media (max-width: 1024px) {
.toc-container {
display: none;
}
.page {
margin-left: 0;
}
}
@media (min-width: 1025px) {
.page {
margin-left: calc(var(--toc-width) + 20px);
}
}

View File

@@ -9,18 +9,13 @@
<script type="module" src="index.mjs"></script>
</head>
<body>
<div class="toc-container">
<div class="toc-list"></div>
</div>
<script id="example_script"></script>
<div class="page">
<p>
<a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a simple
functional C++ library for terminal user interface. <br/>
This showcases the: <a
href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a>
folder. See <a id="source">source</a>.
This showcases the: <a href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a> folder. <br/>
</p>
<div id="terminalContainer">

View File

@@ -7,7 +7,7 @@ if ("serviceWorker" in navigator && !window.crossOriginIsolated) {
const url_sw = new URL("./sw.js", location.href);
const registration = await navigator.serviceWorker.register(url_sw);
window.location.reload(); // Reload to ensure the COOP/COEP headers are set.
}
}
const example_list = "@EXAMPLES@".split(";");
const url_search_params = new URLSearchParams(window.location.search);
@@ -55,7 +55,7 @@ const stdout = code => {
const stderr = code => {
if (code == 0 || code == 10) {
console.error(String.fromCodePoint(...stderr_buffer));
stderr_buffer.length = 0;
stderr_buffer = [];
} else {
stderr_buffer.push(code)
}
@@ -89,72 +89,12 @@ window.Module = {
const resize_observer = new ResizeObserver(resize_handler);
resize_observer.observe(term_element);
resize_handler();
// Disable scrollbar
//term.write('\x1b[?47h')
},
};
const source = document.querySelector("#source");
source.href = "https://github.com/ArthurSonzogni/FTXUI/blob/main/examples/" + example + ".cpp";
const words = example.split('/')
words[1] = "ftxui_example_" + words[1] + ".js"
document.querySelector("#example_script").src = words.join('/');
// Table of Contents (TOC) for quick navigation.
// Get select element
const selectEl = document.querySelector('select#selectExample');
if (!selectEl) {
console.error('select#selectExample not found');
} else {
// Get TOC container
const tocContainer = document.querySelector('.toc-container');
const tocList = tocContainer.querySelector('.toc-list');
// Group options by directory
const groupedOptions = Array.from(selectEl.options).reduce((acc, option) => {
const [dir, file] = option.text.split('/');
if (!acc[dir]) {
acc[dir] = [];
}
acc[dir].push({ option, file });
return acc;
}, {});
// Generate TOC items
for (const dir in groupedOptions) {
const dirContainer = document.createElement('div');
const dirHeader = document.createElement('div');
dirHeader.textContent = dir;
dirHeader.className = 'toc-title';
dirContainer.appendChild(dirHeader);
groupedOptions[dir].forEach(({ option, file }) => {
const tocItem = document.createElement('div');
tocItem.textContent = file;
tocItem.className = 'toc-item';
if (selectEl.options[selectEl.selectedIndex].value === option.value) {
tocItem.classList.add('selected');
}
// Click handler
tocItem.addEventListener('click', () => {
for(let i=0; i<selectEl.options.length; ++i) {
if (selectEl.options[i].value == option.value) {
selectEl.selectedIndex = i;
break;
}
}
history.pushState({}, "", "?file=" + option.value);
location.reload();
});
dirContainer.appendChild(tocItem);
});
tocList.appendChild(dirContainer);
}
}''

View File

@@ -8,21 +8,11 @@
#include <functional> // for function
namespace ftxui::animation {
/// @brief RequestAnimationFrame is a function that requests a new frame to be
/// drawn in the next animation cycle.
///
/// @note This function is typically called by components that need to
/// update their state or appearance over time, such as animations or
/// transitions. This is useful when the change doesn't depend depend on the
/// events seen by the terminal, but rather on the passage of time.
///
/// Components who haven't completed their animation can call this function to
/// request a new frame to be drawn later.
///
/// When there is no new events and no animations to complete, no new frame is
/// drawn.
///
/// @ingroup component
// Components who haven't completed their animation can call this function to
// request a new frame to be drawn later.
//
// When there is no new events and no animations to complete, no new frame is
// drawn.
void RequestAnimationFrame();
using Clock = std::chrono::steady_clock;

View File

@@ -7,7 +7,6 @@
#include <memory>
namespace ftxui {
class CapturedMouseInterface {
public:
CapturedMouseInterface() = default;

View File

@@ -8,7 +8,6 @@
#include <memory> // for make_shared, shared_ptr
#include <utility> // for forward
#include <ftxui/util/warn_windows_macro.hpp>
#include "ftxui/component/component_base.hpp" // for Component, Components
#include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, MenuOption
#include "ftxui/dom/elements.hpp" // for Element

View File

@@ -9,9 +9,8 @@
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Left, Direction::Right, Direction::Down
#include <ftxui/dom/elements.hpp> // for Element, separator
#include <ftxui/util/ref.hpp> // for Ref, ConstRef, StringRef
#include <ftxui/util/warn_windows_macro.hpp>
#include <functional> // for function
#include <string> // for string
#include <functional> // for function
#include <string> // for string
#include "ftxui/component/component_base.hpp" // for Component
#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White
@@ -28,8 +27,6 @@ struct EntryState {
int index; ///< Index of the entry when applicable or -1.
};
/// @brief Option for the underline effect.
/// @ingroup component
struct UnderlineOption {
bool enabled = false;
@@ -233,8 +230,7 @@ struct SliderOption {
std::function<void()> on_change; ///> Called when `value` is updated.
};
/// @brief State passed to the `Window` component's render function.
/// @ingroup component
// Parameter pack used by `WindowOptions::render`.
struct WindowRenderState {
Element inner; ///< The element wrapped inside this window.
const std::string& title; ///< The title of the window.

View File

@@ -24,8 +24,6 @@ class ComponentBase;
///
/// Useful documentation about xterm specification:
/// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
///
/// @ingroup component
struct Event {
// --- Constructor section ---------------------------------------------------
static Event Character(std::string);

View File

@@ -14,45 +14,6 @@ class ComponentBase;
using Component = std::shared_ptr<ComponentBase>;
class ScreenInteractive;
/// @brief Loop is a class that manages the event loop for a component.
///
/// It is responsible for running the component, handling events, and
/// updating the screen.
///
/// The Loop class is designed to be used with a ScreenInteractive object,
/// which represents the terminal screen.
///
/// **Example**
/// ```cpp
/// #include <ftxui/component/component.hpp>
/// #include <ftxui/component/screen_interactive.hpp>
/// #include <ftxui/component/loop.hpp>
///
/// int main() {
/// auto screen = ftxui::ScreenInteractive::TerminalOutput();
/// auto component = ftxui::Button("Click me", [] { ... });
///
/// ftxui::Loop loop(screen.get(), component);
///
/// // Either
/// loop.Run(); // Blocking until the component quits.
///
/// // Or
/// loop.RunOnce(); // Non-blocking, returns immediately.
///
/// // Or
/// loop.RunOnceBlocking(); // Blocking until handling one event.
///
/// // Or in a loop:
/// while (!loop.HasQuitted()) {
/// loop.RunOnce();
///
/// // Do something else like running a different library loop function.
/// }
/// }
/// ```
///
/// @ingroup component
class Loop {
public:
Loop(ScreenInteractive* screen, Component component);

View File

@@ -4,7 +4,6 @@
#ifndef FTXUI_COMPONENT_RECEIVER_HPP_
#define FTXUI_COMPONENT_RECEIVER_HPP_
#include <ftxui/util/warn_windows_macro.hpp>
#include <algorithm> // for copy, max
#include <atomic> // for atomic, __atomic_base
#include <condition_variable> // for condition_variable
@@ -15,8 +14,6 @@
namespace ftxui {
// Deprecated
//
// Usage:
//
// Initialization:
@@ -42,24 +39,17 @@ namespace ftxui {
// Receiver::Receive() returns true when there are no more senders.
// clang-format off
// Deprecated:
template<class T> class SenderImpl;
// Deprecated:
template<class T> class ReceiverImpl;
// Deprecated:
// Deprecated:
template<class T> using Sender = std::unique_ptr<SenderImpl<T>>;
// Deprecated:
template<class T> using Receiver = std::unique_ptr<ReceiverImpl<T>>;
// Deprecated:
template<class T> Receiver<T> MakeReceiver();
// clang-format on
// ---- Implementation part ----
template <class T>
// Deprecated:
class SenderImpl {
public:
SenderImpl(const SenderImpl&) = delete;

View File

@@ -4,10 +4,13 @@
#ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#include <atomic> // for atomic
#include <functional> // for function
#include <memory> // for shared_ptr
#include <string> // for string
#include <atomic> // for atomic
#include <ftxui/component/receiver.hpp> // for Receiver, Sender
#include <functional> // for function
#include <memory> // for shared_ptr
#include <string> // for string
#include <thread> // for thread
#include <variant> // for variant
#include "ftxui/component/animation.hpp" // for TimePoint
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
@@ -24,14 +27,6 @@ struct Event;
using Component = std::shared_ptr<ComponentBase>;
class ScreenInteractivePrivate;
namespace task {
class TaskRunner;
}
/// @brief ScreenInteractive is a `Screen` that can handle events, run a main
/// loop, and manage components.
///
/// @ingroup component
class ScreenInteractive : public Screen {
public:
// Constructors:
@@ -42,9 +37,6 @@ class ScreenInteractive : public Screen {
static ScreenInteractive FitComponent();
static ScreenInteractive TerminalOutput();
// Destructor.
~ScreenInteractive();
// Options. Must be called before Loop().
void TrackMouse(bool enable = true);
@@ -102,10 +94,6 @@ class ScreenInteractive : public Screen {
void Signal(int signal);
void FetchTerminalEvents();
void PostAnimationTask();
ScreenInteractive* suspended_screen_ = nullptr;
enum class Dimension {
FitComponent,
@@ -113,26 +101,30 @@ class ScreenInteractive : public Screen {
Fullscreen,
TerminalOutput,
};
ScreenInteractive(Dimension dimension,
int dimx,
Dimension dimension_ = Dimension::Fixed;
bool use_alternative_screen_ = false;
ScreenInteractive(int dimx,
int dimy,
Dimension dimension,
bool use_alternative_screen);
const Dimension dimension_;
const bool use_alternative_screen_;
bool track_mouse_ = true;
Sender<Task> task_sender_;
Receiver<Task> task_receiver_;
std::string set_cursor_position;
std::string reset_cursor_position;
std::atomic<bool> quit_{false};
std::thread event_listener_;
std::thread animation_listener_;
bool animation_requested_ = false;
animation::TimePoint previous_animation_time_;
int cursor_x_ = 1;
int cursor_y_ = 1;
std::uint64_t frame_count_ = 0;
bool mouse_captured = false;
bool previous_frame_resized_ = false;
@@ -160,14 +152,8 @@ class ScreenInteractive : public Screen {
std::unique_ptr<Selection> selection_;
std::function<void()> selection_on_change_;
// PIMPL private implementation idiom (Pimpl).
struct Internal;
std::unique_ptr<Internal> internal_;
friend class Loop;
Component component_;
public:
class Private {
public:

View File

@@ -20,21 +20,6 @@
namespace ftxui {
/// @brief Canvas is a drawable buffer associated with drawing operations.
///
/// Canvas is a drawable area that can be used to create complex graphics. It
/// supports drawing points, lines, circles, ellipses, text, and images using
/// braille, block, or normal characters.
///
/// Note: A terminal contains cells. A cells is a unit of:
/// - 2x4 braille characters (1x1 pixel)
/// - 2x2 block characters (2x2 pixels)
/// - 2x4 normal characters (2x4 pixels)
///
/// You need to multiply the x coordinate by 2 and the y coordinate by 4 to
/// get the correct position in the terminal.
///
/// @ingroup dom
struct Canvas {
public:
Canvas() = default;

View File

@@ -5,11 +5,6 @@
#define FTXUI_DOM_DIRECTION_HPP
namespace ftxui {
/// @brief Direction is an enumeration that represents the four cardinal
/// directions.
///
/// @ingroup dom
enum class Direction {
Up = 0,
Down = 1,

View File

@@ -24,14 +24,6 @@ using Elements = std::vector<Element>;
using Decorator = std::function<Element(Element)>;
using GraphFunction = std::function<std::vector<int>(int, int)>;
/// @brief BorderStyle is an enumeration that represents the different styles
/// of borders that can be applied to elements in the terminal UI.
///
/// BorderStyle is an enumeration that represents the different styles of
/// borders that can be applied to elements in the terminal UI.
/// It is used to define the visual appearance of borders around elements,
/// such as windows, frames, or separators.
/// @ingroup dom
enum BorderStyle {
LIGHT,
DASHED,

View File

@@ -12,18 +12,6 @@
namespace ftxui {
/// @brief FlexboxConfig is a configuration structure that defines the layout
/// properties for a flexbox container.
//
/// It allows you to specify the direction of the flex items, whether they
/// should wrap, how they should be justified along the main axis, and how
/// they should be aligned along the cross axis.
/// It also includes properties for gaps between flex items in both the
/// main and cross axes.
/// This structure is used to configure the layout behavior of flexbox
/// containers in a terminal user interface.
///
/// @ingroup dom
struct FlexboxConfig {
/// This establishes the main-axis, thus defining the direction flex items are
/// placed in the flex container. Flexbox is (aside wrapping) single-direction

View File

@@ -27,15 +27,8 @@ namespace ftxui {
/// LinearGradient(Color::Red, Color::Blue);
/// LinearGradient(45, Color::Red, Color::Blue);
/// ```
///
/// @ingroup dom
struct LinearGradient {
float angle = 0.f;
/// A stop is a color at a specific position in the gradient.
/// The position is a value between 0.0 and 1.0,
/// where 0.0 is the start of the gradient
/// and 1.0 is the end of the gradient.
struct Stop {
Color color = Color::Default;
std::optional<float> position;

View File

@@ -20,20 +20,6 @@ class Screen;
using Element = std::shared_ptr<Node>;
using Elements = std::vector<Element>;
/// @brief Node is the base class for all elements in the DOM tree.
///
/// It represents a single node in the document object model (DOM) and provides
/// the basic structure for layout and rendering.
/// It contains methods for computing layout requirements, setting the box
/// dimensions, selecting content, rendering to the screen, and checking the
/// layout status.
/// It typically contains child elements, which are also instances of Node.
///
/// Users are expected to derive from this class to create custom elements.
///
/// A list of builtin elements can be found in the `elements.hpp` file.
///
/// @ingroup dom
class Node {
public:
Node();

View File

@@ -10,11 +10,6 @@
namespace ftxui {
class Node;
/// @brief Requirement is a structure that defines the layout requirements for a
/// Node in the terminal user interface.
///
/// It specifies the minimum size required to fully draw the element,
/// @ingroup dom
struct Requirement {
// The required size to fully draw the element.
int min_x = 0;

View File

@@ -13,12 +13,7 @@
namespace ftxui {
/// @brief Represents a selection in a terminal user interface.
///
/// Selection is a class that represents the two endpoints of a selection in a
/// terminal user interface.
///
/// @ingroup dom
/// @brief Represent a selection in the terminal.
class Selection {
public:
Selection(); // Empty selection.

View File

@@ -11,28 +11,28 @@
namespace ftxui {
// Usage:
//
// Initialization:
// ---------------
//
// auto table = Table({
// {"X", "Y"},
// {"-1", "1"},
// {"+0", "0"},
// {"+1", "1"},
// });
//
// table.SelectAll().Border(LIGHT);
//
// table.SelectRow(1).Border(DOUBLE);
// table.SelectRow(1).SeparatorInternal(Light);
//
// std::move(table).Element();
class Table;
class TableSelection;
/// @brief Table is a utility to draw tables.
///
/// **example**
/// ```cpp
/// auto table = Table({
/// {"X", "Y"},
/// {"-1", "1"},
/// {"+0", "0"},
/// {"+1", "1"},
/// });
///
/// table.SelectAll().Border(LIGHT);
/// table.SelectRow(1).Border(DOUBLE);
/// table.SelectRow(1).SeparatorInternal(LIGHT);
///
/// std::move(table).Render();
/// ```
///
/// @ingroup dom
class Table {
public:
Table();

View File

@@ -6,13 +6,6 @@
namespace ftxui {
/// @brief Box is a structure that represents a rectangular area in a 2D space.
///
/// It is defined by its minimum and maximum coordinates along the x and y axes.
/// Note that the coordinates are inclusive, meaning that the box includes both
/// the minimum and maximum values.
///
/// @ingroup screen
struct Box {
int x_min = 0;
int x_max = 0;

View File

@@ -15,9 +15,7 @@
namespace ftxui {
/// @brief Color is a class that represents a color in the terminal user
/// interface.
///
/// @brief A class representing terminal colors.
/// @ingroup screen
class Color {
public:

View File

@@ -9,10 +9,6 @@
namespace ftxui {
/// @brief ColorInfo is a structure that contains information about the terminal
/// color palette.
///
/// @ingroup screen
struct ColorInfo {
const char* name;
uint8_t index_256;

View File

@@ -20,9 +20,6 @@ class Image {
Image() = delete;
Image(int dimx, int dimy);
// Destructor:
virtual ~Image() = default;
// Access a character in the grid at a given position.
std::string& at(int x, int y);
const std::string& at(int x, int y) const;

View File

@@ -11,6 +11,7 @@
#include "ftxui/screen/image.hpp" // for Pixel, Image
#include "ftxui/screen/terminal.hpp" // for Dimensions
#include "ftxui/util/autoreset.hpp" // for AutoReset
namespace ftxui {
@@ -30,9 +31,6 @@ class Screen : public Image {
static Screen Create(Dimensions dimension);
static Screen Create(Dimensions width, Dimensions height);
// Destructor:
~Screen() override = default;
std::string ToString() const;
// Print the Screen on to the terminal.
@@ -60,7 +58,7 @@ class Screen : public Image {
BarBlinking = 5,
Bar = 6,
};
Shape shape = Hidden;
Shape shape;
};
Cursor cursor() const { return cursor_; }

View File

@@ -5,9 +5,6 @@
#define FTXUI_SCREEN_TERMINAL_HPP
namespace ftxui {
/// @brief Dimensions is a structure that represents the size of the terminal
/// @ingroup screen
struct Dimensions {
int dimx;
int dimy;
@@ -17,9 +14,6 @@ namespace Terminal {
Dimensions Size();
void SetFallbackSize(const Dimensions& fallbackSize);
/// @brief Color is an enumeration that represents the color support of the
/// terminal.
/// @ingroup screen
enum Color {
Palette1,
Palette16,

View File

@@ -1,18 +0,0 @@
// Copyright 2025 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
#ifndef FTXUI_UTIL_WARN_WINDOWS_MACRO_H_
#define FTXUI_UTIL_WARN_WINDOWS_MACRO_H_
#ifdef min
#error \
"The macro 'min' is defined, which conflicts with the standard C++ library and FTXUI. This is often caused by including <windows.h>. To fix this, add '#define NOMINMAX' before including <windows.h>, or pass '/DNOMINMAX' as a compiler flag."
#endif
#ifdef max
#error \
"The macro 'max' is defined, which conflicts with the standard C++ library and FTXUI. This is often caused by including <windows.h>. To fix this, add '#define NOMINMAX' before including <windows.h>, or pass '/DNOMINMAX' as a compiler flag."
#endif
#endif // FTXUI_UTIL_WARN_WINDOWS_MACRO_H_

View File

@@ -1,16 +0,0 @@
/// @module ftxui.component
/// @brief Module file for FTXUI component operations.
export module ftxui.component;
export import ftxui.component.animation;
export import ftxui.component.captured_mouse;
export import ftxui.component.component;
export import ftxui.component.component_base;
export import ftxui.component.component_options;
export import ftxui.component.event;
export import ftxui.component.loop;
export import ftxui.component.mouse;
export import ftxui.component.receiver;
export import ftxui.component.screen_interactive;
export import ftxui.component.task;

View File

@@ -1,65 +0,0 @@
/// @module ftxui.component.animation
/// @brief C++20 module interface for the Animation namespace of the Component module.
///
module;
#include <ftxui/component/animation.hpp>
export module ftxui.component.animation;
/**
* @namespace ftxui::animation
* @brief The FTXUI ftxui::animation:: namespace
*/
export namespace ftxui::animation {
using ftxui::animation::RequestAnimationFrame;
using ftxui::animation::Clock;
using ftxui::animation::TimePoint;
using ftxui::animation::Duration;
using ftxui::animation::Params;
/**
* @namespace easing
* @brief The FTXUI sf::animation::easing:: namespace
*/
namespace easing {
using ftxui::animation::easing::Function;
using ftxui::animation::easing::Linear;
using ftxui::animation::easing::QuadraticIn;
using ftxui::animation::easing::QuadraticOut;
using ftxui::animation::easing::QuadraticInOut;
using ftxui::animation::easing::CubicIn;
using ftxui::animation::easing::CubicOut;
using ftxui::animation::easing::CubicInOut;
using ftxui::animation::easing::QuarticIn;
using ftxui::animation::easing::QuarticOut;
using ftxui::animation::easing::QuarticInOut;
using ftxui::animation::easing::QuinticIn;
using ftxui::animation::easing::QuinticOut;
using ftxui::animation::easing::QuinticInOut;
using ftxui::animation::easing::SineIn;
using ftxui::animation::easing::SineOut;
using ftxui::animation::easing::SineInOut;
using ftxui::animation::easing::CircularIn;
using ftxui::animation::easing::CircularOut;
using ftxui::animation::easing::CircularInOut;
using ftxui::animation::easing::ExponentialIn;
using ftxui::animation::easing::ExponentialOut;
using ftxui::animation::easing::ExponentialInOut;
using ftxui::animation::easing::ElasticIn;
using ftxui::animation::easing::ElasticOut;
using ftxui::animation::easing::ElasticInOut;
using ftxui::animation::easing::BackIn;
using ftxui::animation::easing::BackOut;
using ftxui::animation::easing::BackInOut;
using ftxui::animation::easing::BounceIn;
using ftxui::animation::easing::BounceOut;
using ftxui::animation::easing::BounceInOut;
}
using ftxui::animation::Animator;
}

View File

@@ -139,6 +139,7 @@ class ButtonBase : public ComponentBase, public ButtonOption {
private:
bool mouse_hover_ = false;
Box box_;
ButtonOption option_;
float animation_background_ = 0;
float animation_foreground_ = 0;
animation::Animator animator_background_ =

View File

@@ -1,16 +0,0 @@
/// @module ftxui.component.captured_mouse
/// @brief Module file for the CapturedMouseInterface class of the Component module
module;
#include <ftxui/component/captured_mouse.hpp>
export module ftxui.component.captured_mouse;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::CapturedMouseInterface;
}

View File

@@ -12,11 +12,11 @@
namespace ftxui {
/// @brief A collapsible component. It displays a checkbox with an arrow. Once
/// activated, the child is displayed.
/// @brief A collapsible component. It display a checkbox with an arrow. Once
/// activated, the children is displayed.
/// @param label The label of the checkbox.
/// @param child The child to display.
/// @param show Hold the state about whether the child is displayed or not.
/// @param child The children to display.
/// @param show Hold the state about whether the children is displayed or not.
///
/// ### Example
/// ```cpp

View File

@@ -35,22 +35,26 @@ ComponentBase::~ComponentBase() {
/// @brief Return the parent ComponentBase, or nul if any.
/// @see Detach
/// @see Parent
/// @ingroup component
ComponentBase* ComponentBase::Parent() const {
return parent_;
}
/// @brief Access the child at index `i`.
/// @ingroup component
Component& ComponentBase::ChildAt(size_t i) {
assert(i < ChildCount()); // NOLINT
return children_[i];
}
/// @brief Returns the number of children.
/// @ingroup component
size_t ComponentBase::ChildCount() const {
return children_.size();
}
/// @brief Return index of the component in its parent. -1 if no parent.
/// @ingroup component
int ComponentBase::Index() const {
if (parent_ == nullptr) {
return -1;
@@ -67,6 +71,7 @@ int ComponentBase::Index() const {
/// @brief Add a child.
/// @@param child The child to be attached.
/// @ingroup component
void ComponentBase::Add(Component child) {
child->Detach();
child->parent_ = this;
@@ -76,6 +81,7 @@ void ComponentBase::Add(Component child) {
/// @brief Detach this child from its parent.
/// @see Detach
/// @see Parent
/// @ingroup component
void ComponentBase::Detach() {
if (parent_ == nullptr) {
return;
@@ -91,6 +97,7 @@ void ComponentBase::Detach() {
}
/// @brief Remove all children.
/// @ingroup component
void ComponentBase::DetachAllChildren() {
while (!children_.empty()) {
children_[0]->Detach();
@@ -100,6 +107,7 @@ void ComponentBase::DetachAllChildren() {
/// @brief Draw the component.
/// Build a ftxui::Element to be drawn on the ftxui::Screen representing this
/// ftxui::ComponentBase. Please override OnRender() to modify the rendering.
/// @ingroup component
Element ComponentBase::Render() {
// Some users might call `ComponentBase::Render()` from
// `T::OnRender()`. To avoid infinite recursion, we use a flag.
@@ -135,6 +143,7 @@ Element ComponentBase::Render() {
/// @brief Draw the component.
/// Build a ftxui::Element to be drawn on the ftxi::Screen representing this
/// ftxui::ComponentBase. This function is means to be overridden.
/// @ingroup component
Element ComponentBase::OnRender() {
if (children_.size() == 1) {
return children_.front()->Render();
@@ -148,6 +157,7 @@ Element ComponentBase::OnRender() {
/// @return True when the event has been handled.
/// The default implementation called OnEvent on every child until one return
/// true. If none returns true, return false.
/// @ingroup component
bool ComponentBase::OnEvent(Event event) { // NOLINT
for (Component& child : children_) { // NOLINT
if (child->OnEvent(event)) {
@@ -160,6 +170,7 @@ bool ComponentBase::OnEvent(Event event) { // NOLINT
/// @brief Called in response to an animation event.
/// @param params the parameters of the animation
/// The default implementation dispatch the event to every child.
/// @ingroup component
void ComponentBase::OnAnimation(animation::Params& params) {
for (const Component& child : children_) {
child->OnAnimation(params);
@@ -168,6 +179,7 @@ void ComponentBase::OnAnimation(animation::Params& params) {
/// @brief Return the currently Active child.
/// @return the currently Active child.
/// @ingroup component
Component ComponentBase::ActiveChild() {
for (auto& child : children_) {
if (child->Focusable()) {
@@ -180,6 +192,7 @@ Component ComponentBase::ActiveChild() {
/// @brief Return true when the component contains focusable elements.
/// The non focusable Components will be skipped when navigating using the
/// keyboard.
/// @ingroup component
bool ComponentBase::Focusable() const {
for (const Component& child : children_) { // NOLINT
if (child->Focusable()) {
@@ -190,6 +203,7 @@ bool ComponentBase::Focusable() const {
}
/// @brief Returns if the element if the currently active child of its parent.
/// @ingroup component
bool ComponentBase::Active() const {
return parent_ == nullptr || parent_->ActiveChild().get() == this;
}
@@ -198,6 +212,7 @@ bool ComponentBase::Active() const {
/// True when the ComponentBase is focused by the user. An element is Focused
/// when it is with all its ancestors the ActiveChild() of their parents, and it
/// Focusable().
/// @ingroup component
bool ComponentBase::Focused() const {
const auto* current = this;
while (current && current->Active()) {
@@ -208,15 +223,18 @@ bool ComponentBase::Focused() const {
/// @brief Make the |child| to be the "active" one.
/// @param child the child to become active.
/// @ingroup component
void ComponentBase::SetActiveChild([[maybe_unused]] ComponentBase* child) {}
/// @brief Make the |child| to be the "active" one.
/// @param child the child to become active.
/// @ingroup component
void ComponentBase::SetActiveChild(Component child) { // NOLINT
SetActiveChild(child.get());
}
/// @brief Configure all the ancestors to give focus to this component.
/// @ingroup component
void ComponentBase::TakeFocus() {
ComponentBase* child = this;
while (ComponentBase* parent = child->parent_) {
@@ -228,6 +246,7 @@ void ComponentBase::TakeFocus() {
/// @brief Take the CapturedMouse if available. There is only one component of
/// them. It represents a component taking priority over others.
/// @param event The event
/// @ingroup component
CapturedMouse ComponentBase::CaptureMouse(const Event& event) { // NOLINT
if (event.screen_) {
return event.screen_->CaptureMouse();

View File

@@ -1,59 +0,0 @@
/// @module ftxui.component.component
/// @brief Module file for the Component classes of the Component module
module;
#include <ftxui/component/component.hpp>
export module ftxui.component.component;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::ButtonOption;
using ftxui::CheckboxOption;
using ftxui::Event;
using ftxui::InputOption;
using ftxui::MenuOption;
using ftxui::RadioboxOption;
using ftxui::MenuEntryOption;
using ftxui::Make;
using ftxui::ComponentDecorator;
using ftxui::ElementDecorator;
using ftxui::operator|;
using ftxui::operator|=;
namespace Container {
using ftxui::Container::Vertical;
using ftxui::Container::Horizontal;
using ftxui::Container::Tab;
using ftxui::Container::Stacked;
}
using ftxui::Button;
using ftxui::Checkbox;
using ftxui::Input;
using ftxui::Menu;
using ftxui::MenuEntry;
using ftxui::Radiobox;
using ftxui::Dropdown;
using ftxui::Toggle;
using ftxui::Slider;
using ftxui::ResizableSplit;
using ftxui::ResizableSplitLeft;
using ftxui::ResizableSplitRight;
using ftxui::ResizableSplitTop;
using ftxui::ResizableSplitBottom;
using ftxui::Renderer;
using ftxui::CatchEvent;
using ftxui::Maybe;
using ftxui::Modal;
using ftxui::Collapsible;
using ftxui::Hoverable;
using ftxui::Window;
}

View File

@@ -1,26 +0,0 @@
/// @module ftxui.component.component_base
/// @brief Module file for the ComponentBase class of the Component module
module;
#include <ftxui/component/component_base.hpp>
export module ftxui.component.component_base;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::Delegate;
using ftxui::Focus;
using ftxui::Event;
namespace animation {
using ftxui::animation::Params;
}
using ftxui::ComponentBase;
using ftxui::Component;
using ftxui::Components;
}

View File

@@ -2,7 +2,6 @@
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
#include <cassert>
#include <ftxui/component/event.hpp>
#include <vector>
#include "ftxui/component/component.hpp"
#include "ftxui/component/terminal_input_parser.hpp"
@@ -23,9 +22,8 @@ bool GeneratorBool(const char*& data, size_t& size) {
std::string GeneratorString(const char*& data, size_t& size) {
int index = 0;
while (index < size && data[index]) {
while (index < size && data[index])
++index;
}
auto out = std::string(data, data + index);
data += index;
@@ -41,9 +39,8 @@ std::string GeneratorString(const char*& data, size_t& size) {
}
int GeneratorInt(const char* data, size_t size) {
if (size == 0) {
if (size == 0)
return 0;
}
auto out = int(data[0]);
data++;
size--;
@@ -115,9 +112,8 @@ Components GeneratorComponents(const char*& data, size_t& size, int depth);
Component GeneratorComponent(const char*& data, size_t& size, int depth) {
depth--;
int value = GeneratorInt(data, size);
if (depth <= 0) {
if (depth <= 0)
return Button(GeneratorString(data, size), [] {});
}
constexpr int value_max = 19;
value = (value % value_max + value_max) % value_max;
@@ -216,17 +212,16 @@ extern "C" int LLVMFuzzerTestOneInput(const char* data, size_t size) {
auto screen =
Screen::Create(Dimension::Fixed(width), Dimension::Fixed(height));
// Generate some events.
std::vector<Event> events;
auto parser =
TerminalInputParser([&](const Event& event) { events.push_back(event); });
for (size_t i = 0; i < size; ++i) {
parser.Add(data[i]);
auto event_receiver = MakeReceiver<Task>();
{
auto parser = TerminalInputParser(event_receiver->MakeSender());
for (size_t i = 0; i < size; ++i)
parser.Add(data[i]);
}
for (const auto& event : events) {
component->OnEvent(event);
Task event;
while (event_receiver->Receive(&event)) {
component->OnEvent(std::get<Event>(event));
auto document = component->Render();
Render(screen, document);
}

View File

@@ -17,6 +17,7 @@ namespace ftxui {
/// @params _active The color when the component is active.
/// @params _duration The duration of the animation.
/// @params _function The easing function of the animation.
/// @ingroup component
void AnimatedColorOption::Set(Color _inactive,
Color _active,
animation::Duration _duration,
@@ -31,6 +32,7 @@ void AnimatedColorOption::Set(Color _inactive,
/// @brief Set how the underline should animate.
/// @param d The duration of the animation.
/// @param f The easing function of the animation.
/// @ingroup component
void UnderlineOption::SetAnimation(animation::Duration d,
animation::easing::Function f) {
SetAnimationDuration(d);
@@ -39,6 +41,7 @@ void UnderlineOption::SetAnimation(animation::Duration d,
/// @brief Set how the underline should animate.
/// @param d The duration of the animation.
/// @ingroup component
void UnderlineOption::SetAnimationDuration(animation::Duration d) {
leader_duration = d;
follower_duration = d;
@@ -46,6 +49,7 @@ void UnderlineOption::SetAnimationDuration(animation::Duration d) {
/// @brief Set how the underline should animate.
/// @param f The easing function of the animation.
/// @ingroup component
void UnderlineOption::SetAnimationFunction(animation::easing::Function f) {
leader_function = f;
follower_function = std::move(f);
@@ -56,6 +60,7 @@ void UnderlineOption::SetAnimationFunction(animation::easing::Function f) {
/// follower.
/// @param f_leader The duration of the animation for the leader.
/// @param f_follower The duration of the animation for the follower.
/// @ingroup component
void UnderlineOption::SetAnimationFunction(
animation::easing::Function f_leader,
animation::easing::Function f_follower) {
@@ -63,8 +68,9 @@ void UnderlineOption::SetAnimationFunction(
follower_function = std::move(f_follower);
}
/// @brief Standard options for a horizontal menu.
/// @brief Standard options for an horizontal menu.
/// This can be useful to implement a tab bar.
/// @ingroup component
// static
MenuOption MenuOption::Horizontal() {
MenuOption option;
@@ -89,6 +95,7 @@ MenuOption MenuOption::Horizontal() {
/// @brief Standard options for an animated horizontal menu.
/// This can be useful to implement a tab bar.
/// @ingroup component
// static
MenuOption MenuOption::HorizontalAnimated() {
auto option = Horizontal();
@@ -98,6 +105,7 @@ MenuOption MenuOption::HorizontalAnimated() {
/// @brief Standard options for a vertical menu.
/// This can be useful to implement a list of selectable items.
/// @ingroup component
// static
MenuOption MenuOption::Vertical() {
MenuOption option;
@@ -119,6 +127,7 @@ MenuOption MenuOption::Vertical() {
/// @brief Standard options for an animated vertical menu.
/// This can be useful to implement a list of selectable items.
/// @ingroup component
// static
MenuOption MenuOption::VerticalAnimated() {
auto option = MenuOption::Vertical();
@@ -139,8 +148,9 @@ MenuOption MenuOption::VerticalAnimated() {
return option;
}
/// @brief Standard options for a horizontal menu with some separator.
/// @brief Standard options for a horitontal menu with some separator.
/// This can be useful to implement a tab bar.
/// @ingroup component
// static
MenuOption MenuOption::Toggle() {
auto option = MenuOption::Horizontal();
@@ -149,6 +159,7 @@ MenuOption MenuOption::Toggle() {
}
/// @brief Create a ButtonOption, highlighted using [] characters.
/// @ingroup component
// static
ButtonOption ButtonOption::Ascii() {
ButtonOption option;
@@ -161,6 +172,7 @@ ButtonOption ButtonOption::Ascii() {
}
/// @brief Create a ButtonOption, inverted when focused.
/// @ingroup component
// static
ButtonOption ButtonOption::Simple() {
ButtonOption option;
@@ -176,6 +188,7 @@ ButtonOption ButtonOption::Simple() {
/// @brief Create a ButtonOption. The button is shown using a border, inverted
/// when focused. This is the current default.
/// @ingroup component
ButtonOption ButtonOption::Border() {
ButtonOption option;
option.transform = [](const EntryState& s) {
@@ -192,6 +205,7 @@ ButtonOption ButtonOption::Border() {
}
/// @brief Create a ButtonOption, using animated colors.
/// @ingroup component
// static
ButtonOption ButtonOption::Animated() {
return Animated(Color::Black, Color::GrayLight, //
@@ -199,6 +213,7 @@ ButtonOption ButtonOption::Animated() {
}
/// @brief Create a ButtonOption, using animated colors.
/// @ingroup component
// static
ButtonOption ButtonOption::Animated(Color color) {
return ButtonOption::Animated(
@@ -209,6 +224,7 @@ ButtonOption ButtonOption::Animated(Color color) {
}
/// @brief Create a ButtonOption, using animated colors.
/// @ingroup component
// static
ButtonOption ButtonOption::Animated(Color background, Color foreground) {
// NOLINTBEGIN
@@ -221,6 +237,7 @@ ButtonOption ButtonOption::Animated(Color background, Color foreground) {
}
/// @brief Create a ButtonOption, using animated colors.
/// @ingroup component
// static
ButtonOption ButtonOption::Animated(Color background,
Color foreground,
@@ -240,6 +257,7 @@ ButtonOption ButtonOption::Animated(Color background,
}
/// @brief Option for standard Checkbox.
/// @ingroup component
// static
CheckboxOption CheckboxOption::Simple() {
auto option = CheckboxOption();
@@ -264,6 +282,7 @@ CheckboxOption CheckboxOption::Simple() {
}
/// @brief Option for standard Radiobox
/// @ingroup component
// static
RadioboxOption RadioboxOption::Simple() {
auto option = RadioboxOption();
@@ -288,6 +307,7 @@ RadioboxOption RadioboxOption::Simple() {
}
/// @brief Standard options for the input component.
/// @ingroup component
// static
InputOption InputOption::Default() {
InputOption option;
@@ -310,6 +330,7 @@ InputOption InputOption::Default() {
}
/// @brief Standard options for a more beautiful input component.
/// @ingroup component
// static
InputOption InputOption::Spacious() {
InputOption option;

View File

@@ -1,31 +0,0 @@
/// @module ftxui.component.component_options
/// @brief Module file for options for the Component class of the Component module
module;
#include <ftxui/component/component_options.hpp>
export module ftxui.component.component_options;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::EntryState;
using ftxui::UnderlineOption;
using ftxui::AnimatedColorOption;
using ftxui::AnimatedColorsOption;
using ftxui::MenuEntryOption;
using ftxui::MenuOption;
using ftxui::ButtonOption;
using ftxui::CheckboxOption;
using ftxui::InputState;
using ftxui::InputOption;
using ftxui::RadioboxOption;
using ftxui::ResizableSplitOption;
using ftxui::SliderOption;
using ftxui::WindowRenderState;
using ftxui::WindowOptions;
using ftxui::DropdownOption;
}

View File

@@ -24,6 +24,7 @@ namespace ftxui {
/// @brief An event corresponding to a given typed character.
/// @param input The character typed by the user.
/// @ingroup component
// static
Event Event::Character(std::string input) {
Event event;
@@ -34,6 +35,7 @@ Event Event::Character(std::string input) {
/// @brief An event corresponding to a given typed character.
/// @param c The character typed by the user.
/// @ingroup component
// static
Event Event::Character(char c) {
return Event::Character(std::string{c});
@@ -41,6 +43,7 @@ Event Event::Character(char c) {
/// @brief An event corresponding to a given typed character.
/// @param c The character typed by the user.
/// @ingroup component
// static
Event Event::Character(wchar_t c) {
return Event::Character(to_string(std::wstring{c}));
@@ -49,6 +52,7 @@ Event Event::Character(wchar_t c) {
/// @brief An event corresponding to a given typed character.
/// @param input The sequence of character send by the terminal.
/// @param mouse The mouse state.
/// @ingroup component
// static
Event Event::Mouse(std::string input, struct Mouse mouse) {
Event event;
@@ -70,6 +74,7 @@ Event Event::CursorShape(std::string input, int shape) {
/// @brief An custom event whose meaning is defined by the user of the library.
/// @param input An arbitrary sequence of character defined by the developer.
/// @ingroup component
// static
Event Event::Special(std::string input) {
Event event;

View File

@@ -1,19 +0,0 @@
/// @module ftxui.component.event
/// @brief Module file for the Event struct of the Component module
module;
#include <ftxui/component/event.hpp>
export module ftxui.component.event;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::ScreenInteractive;
using ftxui::ComponentBase;
using ftxui::Event;
}

View File

@@ -11,6 +11,7 @@ namespace ftxui {
/// @brief A Loop is a wrapper around a Component and a ScreenInteractive.
/// It is used to run a Component in a terminal.
/// @ingroup component
/// @see Component, ScreenInteractive.
/// @see ScreenInteractive::Loop().
/// @see ScreenInteractive::ExitLoop().
@@ -27,6 +28,7 @@ Loop::~Loop() {
}
/// @brief Whether the loop has quitted.
/// @ingroup component
bool Loop::HasQuitted() {
return screen_->HasQuitted();
}

View File

@@ -1,20 +0,0 @@
/// @module ftxui.component.loop
/// @brief Module file for the Loop class of the Component module
module;
#include <ftxui/component/loop.hpp>
export module ftxui.component.loop;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::ComponentBase;
using ftxui::Component;
using ftxui::ScreenInteractive;
using ftxui::Loop;
}

View File

@@ -15,7 +15,7 @@ namespace ftxui {
/// @brief Decorate a component |child|. It is shown only when |show| returns
/// true.
/// @param child the component to decorate.
/// @param child the compoenent to decorate.
/// @param show a function returning whether |child| should shown.
/// @ingroup component
Component Maybe(Component child, std::function<bool()> show) {
@@ -61,7 +61,7 @@ ComponentDecorator Maybe(std::function<bool()> show) {
}
/// @brief Decorate a component |child|. It is shown only when |show| is true.
/// @param child the component to decorate.
/// @param child the compoennt to decorate.
/// @param show a boolean. |child| is shown when |show| is true.
/// @ingroup component
///

View File

@@ -1,16 +0,0 @@
/// @module ftxui.component.mouse
/// @brief Module file for the Mouse struct of the Component module
module;
#include <ftxui/component/mouse.hpp>
export module ftxui.component.mouse;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::Mouse;
}

View File

@@ -1,26 +0,0 @@
/// @module ftxui.component.receiver
/// @brief Module file for the Receiver class of the Component module
module;
#include <ftxui/component/receiver.hpp>
export module ftxui.component.receiver;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
// Deprecated:
using ftxui::SenderImpl;
// Deprecated:
using ftxui::ReceiverImpl;
// Deprecated:
using ftxui::Sender;
// Deprecated:
using ftxui::Receiver;
// Deprecated:
using ftxui::MakeReceiver;
// Deprecated:
}

View File

@@ -0,0 +1,81 @@
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
#include <thread> // for thread
#include <utility> // for move
#include "ftxui/component/receiver.hpp"
#include "gtest/gtest.h" // for AssertionResult, Message, Test, TestPartResult, EXPECT_EQ, EXPECT_TRUE, EXPECT_FALSE, TEST
// NOLINTBEGIN
namespace ftxui {
TEST(Receiver, Basic) {
auto receiver = MakeReceiver<char>();
auto sender = receiver->MakeSender();
sender->Send('a');
sender->Send('b');
sender->Send('c');
sender.reset();
char a, b, c, d;
EXPECT_TRUE(receiver->Receive(&a));
EXPECT_TRUE(receiver->Receive(&b));
EXPECT_TRUE(receiver->Receive(&c));
EXPECT_FALSE(receiver->Receive(&d));
EXPECT_EQ(a, 'a');
EXPECT_EQ(b, 'b');
EXPECT_EQ(c, 'c');
}
TEST(Receiver, BasicWithThread) {
auto r1 = MakeReceiver<char>();
auto r2 = MakeReceiver<char>();
auto r3 = MakeReceiver<char>();
auto s1 = r1->MakeSender();
auto s2 = r2->MakeSender();
auto s3 = r3->MakeSender();
auto s1_bis = r1->MakeSender();
auto stream = [](Receiver<char> receiver, Sender<char> sender) {
char c;
while (receiver->Receive(&c))
sender->Send(c);
};
// Convert data from a different thread.
auto t12 = std::thread(stream, std::move(r1), std::move(s2));
auto t23 = std::thread(stream, std::move(r2), std::move(s3));
// Send some data.
s1->Send('1');
s1_bis->Send('2');
s1->Send('3');
s1_bis->Send('4');
// Close the stream.
s1.reset();
s1_bis.reset();
char c;
EXPECT_TRUE(r3->Receive(&c));
EXPECT_EQ(c, '1');
EXPECT_TRUE(r3->Receive(&c));
EXPECT_EQ(c, '2');
EXPECT_TRUE(r3->Receive(&c));
EXPECT_EQ(c, '3');
EXPECT_TRUE(r3->Receive(&c));
EXPECT_EQ(c, '4');
EXPECT_FALSE(r3->Receive(&c));
// Thread will end at the end of the stream.
t12.join();
t23.join();
}
} // namespace ftxui
// NOLINTEND

View File

@@ -17,22 +17,24 @@
#include <memory>
#include <stack> // for stack
#include <string>
#include <thread> // for thread, sleep_for
#include <tuple> // for _Swallow_assign, ignore
#include <utility> // for move, swap
#include <variant> // for visit, variant
#include <vector> // for vector
#include <thread> // for thread, sleep_for
#include <tuple> // for _Swallow_assign, ignore
#include <type_traits> // for decay_t
#include <utility> // for move, swap
#include <variant> // for visit, variant
#include <vector> // for vector
#include "ftxui/component/animation.hpp" // for TimePoint, Clock, Duration, Params, RequestAnimationFrame
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/event.hpp" // for Event
#include "ftxui/component/loop.hpp" // for Loop
#include "ftxui/component/task_runner.hpp"
#include "ftxui/component/receiver.hpp" // for ReceiverImpl, Sender, MakeReceiver, SenderImpl, Receiver
#include "ftxui/component/terminal_input_parser.hpp" // for TerminalInputParser
#include "ftxui/dom/node.hpp" // for Node, Render
#include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/pixel.hpp" // for Pixel
#include "ftxui/screen/terminal.hpp" // for Dimensions, Size
#include "ftxui/screen/util.hpp" // for util::clamp
#include "ftxui/util/autoreset.hpp" // for AutoReset
#if defined(_WIN32)
#define DEFINE_CONSOLEV2_PROPERTIES
@@ -45,11 +47,9 @@
#error Must be compiled in UNICODE mode
#endif
#else
#include <fcntl.h>
#include <sys/select.h> // for select, FD_ISSET, FD_SET, FD_ZERO, fd_set, timeval
#include <termios.h> // for tcsetattr, termios, tcgetattr, TCSANOW, cc_t, ECHO, ICANON, VMIN, VTIME
#include <unistd.h> // for STDIN_FILENO, read
#include <cerrno>
#endif
// Quick exit is missing in standard CLang headers
@@ -59,20 +59,6 @@
namespace ftxui {
struct ScreenInteractive::Internal {
// Convert char to Event.
TerminalInputParser terminal_input_parser;
task::TaskRunner task_runner;
// The last time a character was received.
std::chrono::time_point<std::chrono::steady_clock> last_char_time =
std::chrono::steady_clock::now();
explicit Internal(std::function<void(Event)> out)
: terminal_input_parser(std::move(out)) {}
};
namespace animation {
void RequestAnimationFrame() {
auto* screen = ScreenInteractive::Active();
@@ -96,9 +82,73 @@ constexpr int timeout_milliseconds = 20;
timeout_milliseconds * 1000;
#if defined(_WIN32)
void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
auto console = GetStdHandle(STD_INPUT_HANDLE);
auto parser = TerminalInputParser(out->Clone());
while (!*quit) {
// Throttle ReadConsoleInput by waiting 250ms, this wait function will
// return if there is input in the console.
auto wait_result = WaitForSingleObject(console, timeout_milliseconds);
if (wait_result == WAIT_TIMEOUT) {
parser.Timeout(timeout_milliseconds);
continue;
}
DWORD number_of_events = 0;
if (!GetNumberOfConsoleInputEvents(console, &number_of_events))
continue;
if (number_of_events <= 0)
continue;
std::vector<INPUT_RECORD> records{number_of_events};
DWORD number_of_events_read = 0;
ReadConsoleInput(console, records.data(), (DWORD)records.size(),
&number_of_events_read);
records.resize(number_of_events_read);
for (const auto& r : records) {
switch (r.EventType) {
case KEY_EVENT: {
auto key_event = r.Event.KeyEvent;
// ignore UP key events
if (key_event.bKeyDown == FALSE)
continue;
std::wstring wstring;
wstring += key_event.uChar.UnicodeChar;
for (auto it : to_string(wstring)) {
parser.Add(it);
}
} break;
case WINDOW_BUFFER_SIZE_EVENT:
out->Send(Event::Special({0}));
break;
case MENU_EVENT:
case FOCUS_EVENT:
case MOUSE_EVENT:
// TODO(mauve): Implement later.
break;
}
}
}
}
#elif defined(__EMSCRIPTEN__)
#include <emscripten.h>
// Read char from the terminal.
void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
auto parser = TerminalInputParser(std::move(out));
char c;
while (!*quit) {
while (read(STDIN_FILENO, &c, 1), c)
parser.Add(c);
emscripten_sleep(1);
parser.Timeout(1);
}
}
extern "C" {
EMSCRIPTEN_KEEPALIVE
void ftxui_on_resize(int columns, int rows) {
@@ -112,8 +162,8 @@ void ftxui_on_resize(int columns, int rows) {
#else // POSIX (Linux & Mac)
int CheckStdinReady() {
timeval tv = {0, 0}; // NOLINT
int CheckStdinReady(int usec_timeout) {
timeval tv = {0, usec_timeout}; // NOLINT
fd_set fds;
FD_ZERO(&fds); // NOLINT
FD_SET(STDIN_FILENO, &fds); // NOLINT
@@ -121,6 +171,24 @@ int CheckStdinReady() {
return FD_ISSET(STDIN_FILENO, &fds); // NOLINT
}
// Read char from the terminal.
void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
auto parser = TerminalInputParser(std::move(out));
while (!*quit) {
if (!CheckStdinReady(timeout_microseconds)) {
parser.Timeout(timeout_milliseconds);
continue;
}
const size_t buffer_size = 100;
std::array<char, buffer_size> buffer; // NOLINT;
size_t l = read(fileno(stdin), buffer.data(), buffer_size); // NOLINT
for (size_t i = 0; i < l; ++i) {
parser.Add(buffer[i]); // NOLINT
}
}
}
#endif
std::stack<Closure> on_exit_functions; // NOLINT
@@ -267,29 +335,38 @@ class CapturedMouseImpl : public CapturedMouseInterface {
std::function<void(void)> callback_;
};
void AnimationListener(std::atomic<bool>* quit, Sender<Task> out) {
// Animation at around 60fps.
const auto time_delta = std::chrono::milliseconds(15);
while (!*quit) {
out->Send(AnimationTask());
std::this_thread::sleep_for(time_delta);
}
}
} // namespace
ScreenInteractive::ScreenInteractive(Dimension dimension,
int dimx,
ScreenInteractive::ScreenInteractive(int dimx,
int dimy,
Dimension dimension,
bool use_alternative_screen)
: Screen(dimx, dimy),
dimension_(dimension),
use_alternative_screen_(use_alternative_screen) {
internal_ = std::make_unique<Internal>(
[&](Event event) { PostEvent(std::move(event)); });
task_receiver_ = MakeReceiver<Task>();
}
// static
ScreenInteractive ScreenInteractive::FixedSize(int dimx, int dimy) {
return {
Dimension::Fixed,
dimx,
dimy,
/*use_alternative_screen=*/false,
Dimension::Fixed,
false,
};
}
/// @ingroup component
/// Create a ScreenInteractive taking the full terminal size. This is using the
/// alternate screen buffer to avoid messing with the terminal content.
/// @note This is the same as `ScreenInteractive::FullscreenAlternateScreen()`
@@ -298,61 +375,54 @@ ScreenInteractive ScreenInteractive::Fullscreen() {
return FullscreenAlternateScreen();
}
/// @ingroup component
/// Create a ScreenInteractive taking the full terminal size. The primary screen
/// buffer is being used. It means if the terminal is resized, the previous
/// content might mess up with the terminal content.
// static
ScreenInteractive ScreenInteractive::FullscreenPrimaryScreen() {
auto terminal = Terminal::Size();
return {
0,
0,
Dimension::Fullscreen,
terminal.dimx,
terminal.dimy,
/*use_alternative_screen=*/false,
};
}
/// Create a ScreenInteractive taking the full terminal size. This is using the
/// alternate screen buffer to avoid messing with the terminal content.
// static
ScreenInteractive ScreenInteractive::FullscreenAlternateScreen() {
auto terminal = Terminal::Size();
return {
Dimension::Fullscreen,
terminal.dimx,
terminal.dimy,
/*use_alternative_screen=*/true,
};
}
/// Create a ScreenInteractive whose width match the terminal output width and
/// the height matches the component being drawn.
// static
ScreenInteractive ScreenInteractive::TerminalOutput() {
auto terminal = Terminal::Size();
return {
Dimension::TerminalOutput,
terminal.dimx,
terminal.dimy, // Best guess.
/*use_alternative_screen=*/false,
};
}
ScreenInteractive::~ScreenInteractive() = default;
/// Create a ScreenInteractive whose width and height match the component being
/// drawn.
// static
ScreenInteractive ScreenInteractive::FitComponent() {
auto terminal = Terminal::Size();
return {
Dimension::FitComponent,
terminal.dimx, // Best guess.
terminal.dimy, // Best guess.
false,
};
}
/// @ingroup component
/// Create a ScreenInteractive taking the full terminal size. This is using the
/// alternate screen buffer to avoid messing with the terminal content.
// static
ScreenInteractive ScreenInteractive::FullscreenAlternateScreen() {
return {
0,
0,
Dimension::Fullscreen,
true,
};
}
// static
ScreenInteractive ScreenInteractive::TerminalOutput() {
return {
0,
0,
Dimension::TerminalOutput,
false,
};
}
// static
ScreenInteractive ScreenInteractive::FitComponent() {
return {
0,
0,
Dimension::FitComponent,
false,
};
}
/// @ingroup component
/// @brief Set whether mouse is tracked and events reported.
/// called outside of the main loop. E.g `ScreenInteractive::Loop(...)`.
/// @param enable Whether to enable mouse event tracking.
@@ -374,14 +444,20 @@ void ScreenInteractive::TrackMouse(bool enable) {
/// @brief Add a task to the main loop.
/// It will be executed later, after every other scheduled tasks.
/// @ingroup component
void ScreenInteractive::Post(Task task) {
internal_->task_runner.PostTask([this, task = std::move(task)]() mutable {
HandleTask(component_, task);
});
// Task/Events sent toward inactive screen or screen waiting to become
// inactive are dropped.
if (!task_sender_) {
return;
}
task_sender_->Send(std::move(task));
}
/// @brief Add an event to the main loop.
/// It will be executed later, after every other scheduled events.
/// @ingroup component
void ScreenInteractive::PostEvent(Event event) {
Post(event);
}
@@ -403,6 +479,7 @@ void ScreenInteractive::RequestAnimationFrame() {
/// @brief Try to get the unique lock about behing able to capture the mouse.
/// @return A unique lock if the mouse is not already captured, otherwise a
/// null.
/// @ingroup component
CapturedMouse ScreenInteractive::CaptureMouse() {
if (mouse_captured) {
return nullptr;
@@ -414,14 +491,16 @@ CapturedMouse ScreenInteractive::CaptureMouse() {
/// @brief Execute the main loop.
/// @param component The component to draw.
/// @ingroup component
void ScreenInteractive::Loop(Component component) { // NOLINT
class Loop loop(this, std::move(component));
loop.Run();
}
/// @brief Return whether the main loop has been quit.
/// @ingroup component
bool ScreenInteractive::HasQuitted() {
return quit_;
return task_receiver_->HasQuitted();
}
// private
@@ -578,15 +657,7 @@ void ScreenInteractive::Install() {
SetConsoleMode(stdin_handle, in_mode);
SetConsoleMode(stdout_handle, out_mode);
#else // POSIX (Linux & Mac)
// #if defined(__EMSCRIPTEN__)
//// Reading stdin isn't blocking.
// int flags = fcntl(0, F_GETFL, 0);
// fcntl(0, F_SETFL, flags | O_NONBLOCK);
//// Restore the terminal configuration on exit.
// on_exit_functions.emplace([flags] { fcntl(0, F_SETFL, flags); });
// #endif
#else
for (const int signal : {SIGWINCH, SIGTSTP}) {
InstallSignalHandler(signal);
}
@@ -659,57 +730,40 @@ void ScreenInteractive::Install() {
Flush();
quit_ = false;
PostAnimationTask();
task_sender_ = task_receiver_->MakeSender();
event_listener_ =
std::thread(&EventListener, &quit_, task_receiver_->MakeSender());
animation_listener_ =
std::thread(&AnimationListener, &quit_, task_receiver_->MakeSender());
}
// private
void ScreenInteractive::Uninstall() {
ExitNow();
event_listener_.join();
animation_listener_.join();
OnExit();
}
// private
// NOLINTNEXTLINE
void ScreenInteractive::RunOnceBlocking(Component component) {
// Set FPS to 60 at most.
const auto time_per_frame = std::chrono::microseconds(16666); // 1s / 60fps
auto time = std::chrono::steady_clock::now();
size_t executed_task = internal_->task_runner.ExecutedTasks();
// Wait for at least one task to execute.
while (executed_task == internal_->task_runner.ExecutedTasks() &&
!HasQuitted()) {
RunOnce(component);
const auto now = std::chrono::steady_clock::now();
const auto delta = now - time;
time = now;
if (delta < time_per_frame) {
const auto sleep_duration = time_per_frame - delta;
std::this_thread::sleep_for(sleep_duration);
}
ExecuteSignalHandlers();
Task task;
if (task_receiver_->Receive(&task)) {
HandleTask(component, task);
}
RunOnce(component);
}
// private
void ScreenInteractive::RunOnce(Component component) {
AutoReset set_component(&component_, component);
ExecuteSignalHandlers();
FetchTerminalEvents();
// Execute the pending tasks from the queue.
const size_t executed_task = internal_->task_runner.ExecutedTasks();
internal_->task_runner.RunUntilIdle();
// If no executed task, we can return early without redrawing the screen.
if (executed_task == internal_->task_runner.ExecutedTasks()) {
return;
Task task;
while (task_receiver_->ReceiveNonBlocking(&task)) {
HandleTask(component, task);
ExecuteSignalHandlers();
}
ExecuteSignalHandlers();
Draw(component);
Draw(std::move(component));
if (selection_data_previous_ != selection_data_) {
selection_data_previous_ = selection_data_;
@@ -730,7 +784,6 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {
// clang-format off
// Handle Event.
if constexpr (std::is_same_v<T, Event>) {
if (arg.is_cursor_position()) {
cursor_x_ = arg.cursor_x();
cursor_y_ = arg.cursor_y();
@@ -877,7 +930,7 @@ void ScreenInteractive::Draw(Component component) {
break;
}
const bool resized = frame_count_ == 0 || (dimx != dimx_) || (dimy != dimy_);
const bool resized = (dimx != dimx_) || (dimy != dimy_);
ResetCursorPosition();
std::cout << ResetPosition(/*clear=*/resized);
@@ -960,7 +1013,6 @@ void ScreenInteractive::Draw(Component component) {
Flush();
Clear();
frame_valid_ = true;
frame_count_++;
}
// private
@@ -970,11 +1022,13 @@ void ScreenInteractive::ResetCursorPosition() {
}
/// @brief Return a function to exit the main loop.
/// @ingroup component
Closure ScreenInteractive::ExitLoopClosure() {
return [this] { Exit(); };
}
/// @brief Exit the main loop.
/// @ingroup component
void ScreenInteractive::Exit() {
Post([this] { ExitNow(); });
}
@@ -982,6 +1036,7 @@ void ScreenInteractive::Exit() {
// private:
void ScreenInteractive::ExitNow() {
quit_ = true;
task_sender_.reset();
}
// private:
@@ -1014,118 +1069,6 @@ void ScreenInteractive::Signal(int signal) {
#endif
}
void ScreenInteractive::FetchTerminalEvents() {
#if defined(_WIN32)
auto get_input_records = [&]() -> std::vector<INPUT_RECORD> {
// Check if there is input in the console.
auto console = GetStdHandle(STD_INPUT_HANDLE);
DWORD number_of_events = 0;
if (!GetNumberOfConsoleInputEvents(console, &number_of_events)) {
return std::vector<INPUT_RECORD>();
}
if (number_of_events <= 0) {
// No input, return.
return std::vector<INPUT_RECORD>();
}
// Read the input events.
std::vector<INPUT_RECORD> records(number_of_events);
DWORD number_of_events_read = 0;
if (!ReadConsoleInput(console, records.data(), (DWORD)records.size(),
&number_of_events_read)) {
return std::vector<INPUT_RECORD>();
}
records.resize(number_of_events_read);
return records;
};
auto records = get_input_records();
if (records.size() == 0) {
const auto timeout =
std::chrono::steady_clock::now() - internal_->last_char_time;
const size_t timeout_microseconds =
std::chrono::duration_cast<std::chrono::microseconds>(timeout).count();
internal_->terminal_input_parser.Timeout(timeout_microseconds);
return;
}
internal_->last_char_time = std::chrono::steady_clock::now();
// Convert the input events to FTXUI events.
// For each event, we call the terminal input parser to convert it to
// Event.
for (const auto& r : records) {
switch (r.EventType) {
case KEY_EVENT: {
auto key_event = r.Event.KeyEvent;
// ignore UP key events
if (key_event.bKeyDown == FALSE) {
continue;
}
std::wstring wstring;
wstring += key_event.uChar.UnicodeChar;
for (auto it : to_string(wstring)) {
internal_->terminal_input_parser.Add(it);
}
} break;
case WINDOW_BUFFER_SIZE_EVENT:
Post(Event::Special({0}));
break;
case MENU_EVENT:
case FOCUS_EVENT:
case MOUSE_EVENT:
// TODO(mauve): Implement later.
break;
}
}
#elif defined(__EMSCRIPTEN__)
// Read chars from the terminal.
// We configured it to be non blocking.
std::array<char, 128> out{};
size_t l = read(STDIN_FILENO, out.data(), out.size());
if (l == 0) {
const auto timeout =
std::chrono::steady_clock::now() - internal_->last_char_time;
const size_t timeout_microseconds =
std::chrono::duration_cast<std::chrono::microseconds>(timeout).count();
internal_->terminal_input_parser.Timeout(timeout_microseconds);
return;
}
internal_->last_char_time = std::chrono::steady_clock::now();
// Convert the chars to events.
for (size_t i = 0; i < l; ++i) {
internal_->terminal_input_parser.Add(out[i]);
}
#else // POSIX (Linux & Mac)
if (!CheckStdinReady()) {
const auto timeout =
std::chrono::steady_clock::now() - internal_->last_char_time;
const size_t timeout_ms =
std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count();
internal_->terminal_input_parser.Timeout(timeout_ms);
return;
}
internal_->last_char_time = std::chrono::steady_clock::now();
// Read chars from the terminal.
std::array<char, 128> out{};
size_t l = read(fileno(stdin), out.data(), out.size());
// Convert the chars to events.
for (size_t i = 0; i < l; ++i) {
internal_->terminal_input_parser.Add(out[i]);
}
#endif
}
void ScreenInteractive::PostAnimationTask() {
Post(AnimationTask());
// Repeat the animation task every 15ms. This correspond to a frame rate
// of around 66fps.
internal_->task_runner.PostDelayedTask([this] { PostAnimationTask(); },
std::chrono::milliseconds(15));
}
bool ScreenInteractive::SelectionData::operator==(
const ScreenInteractive::SelectionData& other) const {
if (empty && other.empty) {

View File

@@ -1,23 +0,0 @@
/// @module ftxui.component.screen_interactive
/// @brief Module file for the ScreenInteractive class of the Component module
module;
#include <ftxui/component/screen_interactive.hpp>
export module ftxui.component.screen_interactive;
/**
* @namespace ftxui
* @brief The FTXUI ftxui:: namespace
*/
export namespace ftxui {
using ftxui::ComponentBase;
using ftxui::Loop;
using ftxui::Event;
using ftxui::Component;
using ftxui::Screen;
using ftxui::ScreenInteractivePrivate;
using ftxui::ScreenInteractive;
}

View File

@@ -10,58 +10,9 @@
#include "ftxui/component/screen_interactive.hpp"
#include "ftxui/dom/elements.hpp" // for text, Element
#if defined(__unix__)
#include <fcntl.h>
#include <unistd.h>
#include <array>
#include <cstdio>
#include <ftxui/component/loop.hpp>
#include <string>
#endif
namespace ftxui {
namespace {
#if defined(__unix__)
// Capture the standard output (stdout) to a string.
class StdCapture {
public:
explicit StdCapture(std::string* captured) : captured_(captured) {
if (pipe(pipefd_) != 0) {
return;
}
old_stdout_ = dup(fileno(stdout));
fflush(stdout);
dup2(pipefd_[1], fileno(stdout));
close(pipefd_[1]); // Close the write end in the parent
}
~StdCapture() {
fflush(stdout);
dup2(old_stdout_, fileno(stdout));
close(old_stdout_);
char buffer[1024];
ssize_t count;
while ((count = read(pipefd_[0], buffer, sizeof(buffer))) > 0) {
captured_->append(buffer, count);
}
close(pipefd_[0]);
}
StdCapture(const StdCapture&) = delete;
StdCapture& operator=(const StdCapture&) = delete;
private:
int pipefd_[2]{-1, -1};
int old_stdout_{-1};
std::string* const captured_;
};
#endif
bool TestSignal(int signal) {
int called = 0;
// The tree of components. This defines how to navigate using the keyboard.
@@ -180,66 +131,4 @@ TEST(ScreenInteractive, CtrlC_NotForced) {
ASSERT_GE(ctrl_c_count, 50);
}
// Regression test for:
// https://github.com/ArthurSonzogni/FTXUI/pull/1064/files
TEST(ScreenInteractive, FixedSizeInitialFrame) {
#if defined(__unix__)
std::string output;
{
auto capture = StdCapture(&output);
auto screen = ScreenInteractive::FixedSize(2, 2);
auto component = Renderer([&] { return text("AB"); });
Loop loop(&screen, component);
loop.RunOnce();
}
using namespace std::string_view_literals;
auto expected =
// Install the ScreenInteractive.
"\0" // Flush stdout.
"\x1BP$q q" // Set cursor shape to 1 (block).
"\x1B\\" // Reset cursor position.
"\x1B[?7l" // Disable line wrapping.
"\x1B[?1000h" // Enable mouse tracking.
"\x1B[?1003h" // Enable mouse motion tracking.
"\x1B[?1015h" // Enable mouse wheel tracking.
"\x1B[?1006h" // Enable SGR mouse tracking.
"\0" // Flush stdout.
// Reset the screen.
"\r" // Reset cursor position.
"\x1B[2K" // Clear the line.
"\x1B[1A" // Move cursor up one line.
"\x1B[2K" // Clear the line.
// Print the document.
"AB\r\n" // Print "AB" and move to the next line.
" " // Print two spaces to fill the line.
// Set cursor position.
"\x1B[1D" // Move cursor left one character.
"\x1B[?25l" // Hide cursor.
// Flush
"\0" // Flush stdout.
// Uninstall the ScreenInteractive.
"\x1B[1C" // Move cursor right one character.
"\x1B[?1006l" // Disable SGR mouse tracking.
"\x1B[?1015l" // Disable mouse wheel tracking.
"\x1B[?1003l" // Disable mouse motion tracking.
"\x1B[?1000l" // Disable mouse tracking.
"\x1B[?7h" // Enable line wrapping.
"\x1B[?25h" // Show cursor.
"\x1B[1 q" // Set cursor shape to 1 (block).
"\0" // Flush stdout.
// Skip one line to avoid the prompt to be printed over the last drawing.
"\r\n"sv;
ASSERT_EQ(expected, output);
#endif
}
} // namespace ftxui

Some files were not shown because too many files have changed in this diff Show More