48 Commits

Author SHA1 Message Date
ArthurSonzogni
f4fdf7a992 Fixes. 2025-06-04 11:42:35 +02:00
ArthurSonzogni
c302ea0752 Use lowercase filenames. 2025-06-03 19:25:16 +02:00
Miko
d7247002d3 Fix hyperlink error 2025-06-03 13:47:42 +00:00
Miko
6aed3877f6 Add XMake package to readme 2025-06-03 13:47:07 +00:00
Miko
756dd601aa Merge branch 'ArthurSonzogni:main' into main 2025-06-03 08:19:36 -04:00
Toyosatomimi no Miko
33f78dd7a8 Restore original whitespace line breaks 2025-06-02 11:02:48 -04:00
Toyosatomimi no Miko
f1dfc8f2f8 Include additional information on module organisation 2025-06-02 10:57:45 -04:00
ArthurSonzogni
9577dfc0b3 Fix build errors. 2025-06-02 16:02:04 +02:00
ArthurSonzogni
4898e859d8 Add the .cppm to Doxygen 2025-06-02 10:34:44 +02:00
ArthurSonzogni
6a783ce9b5 Revert examples change + add doc. 2025-06-02 10:28:16 +02:00
ArthurSonzogni
a4a4e20902 Fix workflow incorrect merge conflict resolution 2025-06-02 10:21:48 +02:00
ArthurSonzogni
ce43ba6bea Add documentation 2025-06-02 10:21:16 +02:00
ArthurSonzogni
7abac6c5f9 Add documentation + fix errors. 2025-06-02 10:20:05 +02:00
Miko
cdc6a61854 Merge branch 'ArthurSonzogni:main' into main 2025-06-01 15:52:30 -04:00
Miko
118949b295 Merge branch 'ArthurSonzogni:main' into main 2025-05-31 23:39:14 -04:00
Miko
bc3657d62a Merge branch 'ArthurSonzogni:main' into main 2025-05-31 01:58:06 -04:00
Miko
6e7c0cb212 Add mention of ftxui.util module 2025-05-29 15:03:54 +00:00
Miko
2d12c4b3db Merge branch 'main' into main 2025-05-29 10:59:54 -04:00
Toyosatomimi no Miko
88a9132d75 Missing italic declaration 2025-05-15 15:31:39 -04:00
Toyosatomimi no Miko
83b83e30ec Missing header (number 2) 2025-05-15 15:24:11 -04:00
Toyosatomimi no Miko
bc45cd6ad5 Missing header 2025-05-15 15:19:03 -04:00
Toyosatomimi no Miko
cdf8144bf1 This should fix the problem. Forgot to export these 2025-05-15 15:07:49 -04:00
Toyosatomimi no Miko
ed5f04ccc0 Update examples for testing modules 2025-05-15 14:54:42 -04:00
Miko
4b8c8ea00d Merge branch 'ArthurSonzogni:main' into main 2025-05-11 17:12:31 -04:00
Miko
9e1120c146 Merge branch 'main' into main 2025-05-10 22:01:04 -04:00
Miko
006ec1cbed Merge branch 'ArthurSonzogni:main' into main 2025-05-04 19:27:15 -04:00
Miko
16c25ae441 Merge branch 'main' into main 2025-05-01 17:09:57 -04:00
Miko
05b4bffe3b Merge branch 'main' into main 2025-04-30 14:39:52 -04:00
Toyosatomimi no Miko
ffc6dcd3bf Add ftxui module for all submodules 2025-04-19 09:54:02 -04:00
ArthurSonzogni
f6dceabdc9 tweaks 2025-04-11 15:07:58 +02:00
ArthurSonzogni
cb8ebdeb44 fix workflows 3 2025-04-11 02:03:18 +02:00
ArthurSonzogni
dd37fba100 Fix workflow 2 2025-04-11 01:48:07 +02:00
ArthurSonzogni
4d627c1ffb Fix workflow. 2025-04-11 01:43:23 +02:00
ArthurSonzogni
1dff6a5c35 Compile examples with modules. 2025-04-11 01:39:07 +02:00
ArthurSonzogni
0c67566427 Update 2025-04-10 14:45:45 +02:00
ArthurSonzogni
85c3dc45ca Add Changelog and remove flag. 2025-04-09 12:35:46 +02:00
Miko
84f691e9d3 Merge branch 'ArthurSonzogni:main' into main 2025-04-08 11:45:52 -04:00
Miko
2e36aa061a Merge branch 'ArthurSonzogni:main' into main 2025-03-29 22:17:54 -04:00
Miko
8ed06a4812 Merge branch 'ArthurSonzogni:main' into main 2025-03-29 12:26:56 -04:00
Toyosatomimi no Miko
571f6dcdcf Trailing newline 2025-03-29 12:26:07 -04:00
Toyosatomimi no Miko
e57c275512 Make modules opt-in (for pre-C++20 builds not to break) 2025-03-28 08:28:05 -04:00
Miko
1c37cdd192 Merge branch 'ArthurSonzogni:main' into main 2025-03-28 08:22:58 -04:00
Miko
772d4ebeed Merge branch 'ArthurSonzogni:main' into main 2025-03-27 23:56:08 -04:00
Miko
5f5bc9019d Delete modules/CMakeLists.txt
No longer needed
2025-03-28 03:54:48 +00:00
Miko
f87b6a4d12 Update CMakeLists.txt
Directly go to `modules/ftxui`
2025-03-28 03:54:25 +00:00
Toyosatomimi no Miko
0d50fa25fe I assume the version produced by CMake was supposed to be bumped up to 6.0.0, fixing this 2025-03-25 19:09:35 -04:00
Toyosatomimi no Miko
730ebeed1d Add my own project (using FTXUI modules) for an example 2025-03-25 18:59:58 -04:00
Toyosatomimi no Miko
69928b374e Add modules support 2025-03-25 18:49:18 -04:00
186 changed files with 1487 additions and 4557 deletions

View File

@@ -1 +0,0 @@
bazel/test/

View File

@@ -1,10 +1,7 @@
common --enable_bzlmod
common --enable_workspace
build --features=layering_check build --features=layering_check
build --enable_bzlmod build --enable_bzlmod
build --enable_platform_specific_config build --enable_platform_specific_config
build:linux --cxxopt=-std=c++20 build:linux --cxxopt=-std=c++20
build:macos --cxxopt=-std=c++20 build:macos --cxxopt=-std=c++20
build:windows --cxxopt=/std:c++20 build:windows --cxxopt=-std:c++20

View File

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

View File

@@ -1,212 +0,0 @@
# FTXUI - Functional Terminal (X) User Interface
FTXUI is a cross-platform C++ library for terminal-based user interfaces with a functional programming approach, inspired by React.
**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the information here.**
## Working Effectively
### Build System Setup and Commands
- Bootstrap and build the repository:
```bash
# Basic build (library only) - fast
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel $(nproc)
# Build time: ~30 seconds. NEVER CANCEL. Set timeout to 120+ seconds.
# Build with examples
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DFTXUI_BUILD_EXAMPLES=ON
cmake --build build --parallel $(nproc)
# Build time: ~70 seconds. NEVER CANCEL. Set timeout to 180+ seconds.
# Build with examples and tests
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DFTXUI_BUILD_EXAMPLES=ON -DFTXUI_BUILD_TESTS=ON
cmake --build build --parallel $(nproc)
# Build time: ~113 seconds (includes GoogleTest download). NEVER CANCEL. Set timeout to 300+ seconds.
```
- Alternative build with Ninja (faster):
```bash
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DFTXUI_BUILD_EXAMPLES=ON
ninja -C build
# Build time: ~62 seconds. NEVER CANCEL. Set timeout to 180+ seconds.
```
- Run unit tests:
```bash
# Configure with tests enabled first, then:
cd build && ctest --output-on-failure
# Test time: ~4 seconds (302 tests). NEVER CANCEL. Set timeout to 60+ seconds.
```
### Bazel Support
- FTXUI also supports Bazel build system
- **WARNING**: Bazel may fail due to network connectivity issues in sandboxed environments
- If Bazel is available:
```bash
bazel build //... # Build everything
bazel test //... # Run tests
```
## Validation
### Manual Testing After Changes
- **ALWAYS manually validate changes by building and running examples after making code modifications**
- Run example applications to verify functionality:
```bash
# Build an example first
cmake --build build --target ftxui_example_border
# Run examples (they are interactive, use timeout to terminate)
timeout 2s build/examples/dom/ftxui_example_border
timeout 2s build/examples/dom/ftxui_example_color_gallery
timeout 2s build/examples/component/ftxui_example_button
```
- Examples should produce visual terminal output with borders, colors, and UI components
- **CRITICAL**: Always run at least one DOM example and one Component example to verify both modules work
### Code Quality and Formatting
- Always run formatting before committing:
```bash
./tools/format.sh
# Format time: ~7 seconds. NEVER CANCEL. Set timeout to 60+ seconds.
```
- The format script adds license headers and runs clang-format on all source files
- **Required**: Run formatting or the CI (.github/workflows/build.yaml) will fail
### Build Validation Requirements
- ALWAYS build with both `-DFTXUI_BUILD_EXAMPLES=ON` and `-DFTXUI_BUILD_TESTS=ON` when making changes
- Run the complete test suite with `ctest --output-on-failure`
- All 302 tests must pass
- **Scenario Testing**: Run at least these validation scenarios:
1. Build library only (basic validation)
2. Build with examples and run 2-3 different examples
3. Build with tests and run complete test suite
4. Run formatting tool to ensure code style compliance
## Project Structure
### Key Directories
```
/home/runner/work/FTXUI/FTXUI/
├── include/ftxui/ # Public header files
│ ├── component/ # Interactive component headers
│ ├── dom/ # DOM element headers
│ ├── screen/ # Screen and rendering headers
│ └── util/ # Utility headers
├── src/ftxui/ # Implementation files
│ ├── component/ # Interactive components (buttons, menus, etc.)
│ ├── dom/ # DOM elements (layout, styling, text)
│ ├── screen/ # Screen rendering and terminal handling
│ └── util/ # Utilities
├── examples/ # Example applications
│ ├── component/ # Interactive component examples
│ └── dom/ # DOM element examples
├── cmake/ # CMake configuration files
├── tools/ # Development tools (formatting, etc.)
└── .github/workflows/ # CI/CD configuration
```
### Core Library Modules
FTXUI is organized into three main modules that depend on each other:
```
┌component──┐ (Interactive UI components)
│┌dom──────┐│ (Layout and styling elements)
││┌screen─┐││ (Terminal rendering and input)
└┴┴───────┴┴┘
```
1. **screen**: Low-level terminal handling, colors, pixels, input
2. **dom**: Layout elements (hbox, vbox, text, borders, etc.)
3. **component**: Interactive components (buttons, menus, input fields)
### CMake Build Options
| Option | Description | Default |
|-----------------------------------|----------------------------------|---------|
| FTXUI_BUILD_EXAMPLES | Build example applications | OFF |
| FTXUI_BUILD_DOCS | Build documentation | OFF |
| FTXUI_BUILD_TESTS | Build and enable tests | OFF |
| FTXUI_BUILD_MODULES | Build C++20 modules | OFF |
| FTXUI_ENABLE_INSTALL | Generate install targets | ON |
| FTXUI_MICROSOFT_TERMINAL_FALLBACK | Windows terminal compatibility | ON/OFF |
## Common Tasks
### Building Examples
```bash
# Build specific examples
cmake --build build --target ftxui_example_border
cmake --build build --target ftxui_example_button
cmake --build build --target ftxui_example_menu
# List all available examples
find build -name "ftxui_example_*" -type f
```
### Running Tests
```bash
# Run all tests
cd build && ctest
# Run tests with verbose output
cd build && ctest --verbose
# Run specific test pattern
cd build && ctest -R "Button" --verbose
```
### Working with Source Code
- **Component Development**: Modify files in `src/ftxui/component/` for interactive elements
- **DOM Development**: Modify files in `src/ftxui/dom/` for layout and styling
- **Screen Development**: Modify files in `src/ftxui/screen/` for terminal rendering
- **Adding Examples**: Add new `.cpp` files in `examples/component/` or `examples/dom/`
- **Header Files**: Public APIs are in `include/ftxui/[module]/`
### Integration Patterns
When adding FTXUI to a project, use CMake FetchContent (recommended):
```cmake
include(FetchContent)
FetchContent_Declare(ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
GIT_TAG v6.1.9
)
FetchContent_MakeAvailable(ftxui)
target_link_libraries(your_target PRIVATE
ftxui::component # For interactive components
ftxui::dom # For layout elements
ftxui::screen # For basic rendering
)
```
## Troubleshooting
### Build Issues
- If CMake configuration fails, ensure C++20 support: `cmake --version` (need 3.12+)
- If Ninja build fails, fall back to Make: `cmake -S . -B build` (without `-G Ninja`)
- If tests fail to build, GoogleTest download might have failed - check network connectivity
- Build artifacts are in `build/` directory - delete with `rm -rf build` to clean
### Example Issues
- Examples are interactive terminal applications - use `timeout` to terminate them
- If examples don't display correctly, terminal might not support colors/Unicode
- Examples require terminal size of at least 80x24 for proper display
### Formatting Issues
- Format script requires clang-format to be installed
- If format script fails, check that source files are not read-only
- Format script modifies files in-place - commit changes afterwards
## Critical Reminders
- **NEVER CANCEL long-running builds** - they may take 2-3 minutes
- **ALWAYS run the formatting tool** before committing changes
- **ALWAYS build and test examples** when making component/dom changes
- **SET APPROPRIATE TIMEOUTS**: 300+ seconds for builds, 60+ seconds for tests
- **BUILD TIMING EXPECTATIONS**:
- Basic library: ~30 seconds
- With examples: ~70 seconds
- With examples + tests: ~113 seconds (first time, includes GoogleTest download)
- Subsequent builds: ~60-70 seconds
- Tests execution: ~4 seconds
- Formatting: ~7 seconds

View File

@@ -56,13 +56,6 @@ jobs:
CXX: ${{ matrix.cxx }} CXX: ${{ matrix.cxx }}
run: bazel test --test_output=all ... run: bazel test --test_output=all ...
- name: "Bazel Smoke test"
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
run: bazel build //... --enable_bzlmod --override_module=ftxui=../..
working-directory: bazel/test
test_cmake: test_cmake:
name: "CMake, ${{ matrix.compiler }}, ${{ matrix.os }}" name: "CMake, ${{ matrix.compiler }}, ${{ matrix.os }}"
strategy: strategy:

View File

@@ -12,10 +12,6 @@ jobs:
steps: steps:
- name: "Checkout repository" - name: "Checkout repository"
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
fetch-depth: 0 # Need full history.
fetch-tags: true # Need tags.
- name: "Install cmake" - name: "Install cmake"
uses: lukka/get-cmake@latest uses: lukka/get-cmake@latest
@@ -34,12 +30,7 @@ jobs:
sudo apt-get install graphviz; sudo apt-get install graphviz;
- name: "Build documentation" - name: "Build documentation"
run: |
python3 ./tools/build_multiversion_doc.py
- name: "Build examples"
run: > run: >
mkdir -p multiversion_docs/main/examples;
mkdir build; mkdir build;
cd build; cd build;
emcmake cmake .. emcmake cmake ..
@@ -50,7 +41,8 @@ jobs:
-DFTXUI_BUILD_TESTS_FUZZER=OFF -DFTXUI_BUILD_TESTS_FUZZER=OFF
-DFTXUI_ENABLE_INSTALL=OFF -DFTXUI_ENABLE_INSTALL=OFF
-DFTXUI_DEV_WARNINGS=OFF; -DFTXUI_DEV_WARNINGS=OFF;
cmake --build .; cmake --build . --target doc;
cmake --build . ;
rsync -amv rsync -amv
--include='*/' --include='*/'
--include='*.html' --include='*.html'
@@ -60,13 +52,13 @@ jobs:
--include='*.wasm' --include='*.wasm'
--exclude='*' --exclude='*'
examples examples
../multiversion_docs/ doc/doxygen/html;
- name: "Deploy" - name: "Deploy"
uses: peaceiris/actions-gh-pages@v3 uses: peaceiris/actions-gh-pages@v3
with: with:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: multiversion_docs publish_dir: build/doc/doxygen/html/
enable_jekyll: false enable_jekyll: false
allow_empty_commit: false allow_empty_commit: false
force_orphan: true force_orphan: true

9
.gitignore vendored
View File

@@ -24,12 +24,10 @@ out/
!BUILD.bazel !BUILD.bazel
!MODULE.bazel !MODULE.bazel
!.bazelrc !.bazelrc
!.bazelignore
# .github directory: # .github directory:
!.github/**/*.yaml !.github/**/*.yaml
!.github/**/*.yml !.github/**/*.yml
!.github/**/*.md
# cmake directory: # cmake directory:
!cmake/**/*.in !cmake/**/*.in
@@ -38,10 +36,6 @@ out/
# bazel directory: # bazel directory:
!bazel/**/*.bzl !bazel/**/*.bzl
!.bcr/* !.bcr/*
!bazel/test/*.bazel
!bazel/test/*.bazelrc
!bazel/test/*.cpp
!bazel/test/*.md
# doc directory: # doc directory:
!doc/**/Doxyfile.in !doc/**/Doxyfile.in
@@ -50,7 +44,6 @@ out/
!doc/**/*.html !doc/**/*.html
!doc/**/*.xml !doc/**/*.xml
!doc/**/*.md !doc/**/*.md
!doc/*.md
# examples directory: # examples directory:
!examples/**/*.cpp !examples/**/*.cpp
@@ -76,6 +69,4 @@ out/
# tools directory: # tools directory:
!tools/**/*.sh !tools/**/*.sh
!tools/**/*.py
!tools/**/*.cpp !tools/**/*.cpp
build/

View File

@@ -13,18 +13,16 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load(":bazel/ftxui.bzl", "ftxui_cc_library") load(":bazel/ftxui.bzl", "ftxui_cc_library")
load(":bazel/ftxui.bzl", "generate_examples") load(":bazel/ftxui.bzl", "generate_examples")
load(":bazel/ftxui.bzl", "windows_copts") load(":bazel/ftxui.bzl", "windows_copts")
load(":bazel/ftxui.bzl", "pthread_linkopts")
# A meta target depending on all of the ftxui submodules. # A meta target depending on all of the ftxui submodules.
# Note that component depends on dom and screen, so ftxui re-exports all headers. # Note that component depends on dom and screen, so ftxui is just an alias for
# component.
# ┌component──┐ # ┌component──┐
# │┌dom──────┐│ # │┌dom──────┐│
# ││┌screen─┐││ # ││┌screen─┐││
# └┴┴───────┴┴┘ # └┴┴───────┴┴┘
ftxui_cc_library( alias(name = "ftxui", actual = ":component")
name = "ftxui",
hdrs = glob(["include/ftxui/**/*.hpp"]),
deps = [":component"],
)
# @ftxui:screen is a module that provides a screen buffer and color management # @ftxui:screen is a module that provides a screen buffer and color management
# for terminal applications. A screen is a 2D array of cells, each cell can # for terminal applications. A screen is a 2D array of cells, each cell can
@@ -161,12 +159,6 @@ ftxui_cc_library(
"src/ftxui/component/resizable_split.cpp", "src/ftxui/component/resizable_split.cpp",
"src/ftxui/component/screen_interactive.cpp", "src/ftxui/component/screen_interactive.cpp",
"src/ftxui/component/slider.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.cpp",
"src/ftxui/component/terminal_input_parser.hpp", "src/ftxui/component/terminal_input_parser.hpp",
"src/ftxui/component/util.cpp", "src/ftxui/component/util.cpp",
@@ -178,9 +170,6 @@ ftxui_cc_library(
# Private header from ftxui:screen. # Private header from ftxui:screen.
"src/ftxui/screen/string_internal.hpp", "src/ftxui/screen/string_internal.hpp",
"src/ftxui/screen/util.hpp", "src/ftxui/screen/util.hpp",
# Private header.
"include/ftxui/util/warn_windows_macro.hpp",
], ],
hdrs = [ hdrs = [
"include/ftxui/component/animation.hpp", "include/ftxui/component/animation.hpp",
@@ -195,6 +184,7 @@ ftxui_cc_library(
"include/ftxui/component/screen_interactive.hpp", "include/ftxui/component/screen_interactive.hpp",
"include/ftxui/component/task.hpp", "include/ftxui/component/task.hpp",
], ],
linkopts = pthread_linkopts(),
deps = [ deps = [
":dom", ":dom",
":screen", ":screen",
@@ -217,6 +207,7 @@ cc_test(
"src/ftxui/component/menu_test.cpp", "src/ftxui/component/menu_test.cpp",
"src/ftxui/component/modal_test.cpp", "src/ftxui/component/modal_test.cpp",
"src/ftxui/component/radiobox_test.cpp", "src/ftxui/component/radiobox_test.cpp",
"src/ftxui/component/receiver_test.cpp",
"src/ftxui/component/resizable_split_test.cpp", "src/ftxui/component/resizable_split_test.cpp",
"src/ftxui/component/slider_test.cpp", "src/ftxui/component/slider_test.cpp",
"src/ftxui/component/terminal_input_parser_test.cpp", "src/ftxui/component/terminal_input_parser_test.cpp",

View File

@@ -24,34 +24,7 @@ Next
import ftxui.util; import ftxui.util;
``` ```
Thanks @mikomikotaishi for PR #1015. Thanks @mikomikotaishi for PR #1015.
- Remove dependency on 'pthread'.
- Bugfix: Bazel target @ftxui is now visible. Thanks @dskkato in #1157.
### General
- Breaking. Move to `std::string_view` instead of `const std::string&` where
applicable. This yields better interoperability with string literals and
avoids unnecessary copies. Thanks @mikomikotaishi for PR #1154
### Component
- Feature: POSIX Piped Input Handling.
- Allows FTXUI applications to read data from stdin (when piped) while still receiving keyboard input from the terminal.
- Enabled by default.
- Can be disabled using `ScreenInteractive::HandlePipedInput(false)`.
- Only available on Linux and macOS.
Thanks @HarryPehkonen for PR #1094.
- 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.
- Fix Windows UTF-16 key input handling. Emoji and other code points outside the
Basic Multilingual Plane (BMP) are now correctly processed. Thanks @739C1AE2
in #1160 for fixing the issue.
### Dom
- Fix integer overflow in `ComputeShrinkHard`. Thanks @its-pablo in #1137 for
reporting and fixing the issue.
- Add specialization for `vbox/hbox/dbox` to allow a container of Element as
as input. Thanks @nbusser in #1117.
6.1.9 (2025-05-07) 6.1.9 (2025-05-07)
------------ ------------

View File

@@ -144,20 +144,26 @@ add_library(component
src/ftxui/component/resizable_split.cpp src/ftxui/component/resizable_split.cpp
src/ftxui/component/screen_interactive.cpp src/ftxui/component/screen_interactive.cpp
src/ftxui/component/slider.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.cpp
src/ftxui/component/terminal_input_parser.hpp src/ftxui/component/terminal_input_parser.hpp
src/ftxui/component/util.cpp src/ftxui/component/util.cpp
src/ftxui/component/window.cpp src/ftxui/component/window.cpp
) )
target_link_libraries(dom PUBLIC screen) target_link_libraries(dom
target_link_libraries(component PUBLIC 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) include(cmake/ftxui_set_options.cmake)
ftxui_set_options(screen) ftxui_set_options(screen)
@@ -178,8 +184,8 @@ include(cmake/ftxui_install.cmake)
include(cmake/ftxui_package.cmake) include(cmake/ftxui_package.cmake)
include(cmake/ftxui_modules.cmake) include(cmake/ftxui_modules.cmake)
add_subdirectory(examples)
add_subdirectory(doc) add_subdirectory(doc)
add_subdirectory(examples)
# You can generate ./examples_modules/ by running # You can generate ./examples_modules/ by running
# ./tools/generate_examples_modules.sh # ./tools/generate_examples_modules.sh

View File

@@ -1,4 +1,3 @@
<p align="center"> <p align="center">
<img src="https://github.com/ArthurSonzogni/FTXUI/assets/4759106/6925b6da-0a7e-49d9-883c-c890e1f36007" alt="Demo image"></img> <img src="https://github.com/ArthurSonzogni/FTXUI/assets/4759106/6925b6da-0a7e-49d9-883c-c890e1f36007" alt="Demo image"></img>
<br/> <br/>
@@ -19,16 +18,10 @@
<br/> <br/>
<a href="https://arthursonzogni.github.io/FTXUI/">Documentation</a> · <a href="https://arthursonzogni.github.io/FTXUI/">Documentation</a> ·
<a href="https://github.com/ArthurSonzogni/FTXUI/issues">Report a Bug</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/issues">Request Feature</a> ·
<a href="https://github.com/ArthurSonzogni/FTXUI/pulls">Send a Pull Request</a> <a href="https://github.com/ArthurSonzogni/FTXUI/pulls">Send a Pull Request</a>
<br/>
<a href="https://github.com/ArthurSonzogni/">English</a> |
<a href="https://github.com/ArthurSonzogni/ftxui-translations/tree/zh-CH">中文翻译</a> |
<a href="https://github.com/ArthurSonzogni/ftxui-translations/tree/zh-CH">繁體中文</a> |
<a href="https://github.com/ArthurSonzogni/ftxui-translations/tree/ja">日本語</a>
</p> </p>
# FTXUI # FTXUI
@@ -59,7 +52,6 @@ A simple cross-platform C++ library for terminal based user interfaces!
- [Arch Linux](https://aur.archlinux.org/packages/ftxui/) - [Arch Linux](https://aur.archlinux.org/packages/ftxui/)
- [OpenSUSE](https://build.opensuse.org/package/show/devel:libraries:c_c++/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) - [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)
* Good practices: documentation, tests, fuzzers, performance tests, automated CI, automated packaging, etc... * Good practices: documentation, tests, fuzzers, performance tests, automated CI, automated packaging, etc...
## Documentation ## Documentation
@@ -105,7 +97,7 @@ Element can be arranged together:
- inside a grid with `gridbox` - inside a grid with `gridbox`
- wrap along one direction using the `flexbox`. - 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`. [Example](https://arthursonzogni.github.io/FTXUI/examples_2dom_2vbox_hbox_8cpp-example.html) using `hbox`, `vbox` and `filler`.
@@ -369,9 +361,6 @@ Feel free to add your projects here:
- [FTB - tertminal file browser](https://github.com/Cyxuan0311/FTB) - [FTB - tertminal file browser](https://github.com/Cyxuan0311/FTB)
- [openJuice](https://github.com/mikomikotaishi/openJuice) - [openJuice](https://github.com/mikomikotaishi/openJuice)
- [SHOOT!](https://github.com/ShingZhanho/ENGG1340-Project-25Spring) - [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)
- [typing-speed-test](https://github.com/ymcx/typing-speed-test)
### [cpp-best-practices/game_jam](https://github.com/cpp-best-practices/game_jam) ### [cpp-best-practices/game_jam](https://github.com/cpp-best-practices/game_jam)
@@ -388,8 +377,6 @@ Several games using the FTXUI have been made during the Game Jam:
- [smoothlife](https://github.com/cpp-best-practices/game_jam/blob/main/Jam1_April_2022/smoothlife.md) - [smoothlife](https://github.com/cpp-best-practices/game_jam/blob/main/Jam1_April_2022/smoothlife.md)
- [Consu](https://github.com/cpp-best-practices/game_jam/blob/main/Jam1_April_2022/consu.md) - [Consu](https://github.com/cpp-best-practices/game_jam/blob/main/Jam1_April_2022/consu.md)
## Build using CMake ## Build using CMake
It is **highly** recommended to use CMake FetchContent to depend on FTXUI so you may specify which commit you would like to depend on. It is **highly** recommended to use CMake FetchContent to depend on FTXUI so you may specify which commit you would like to depend on.
@@ -425,13 +412,9 @@ cc_binary(
name = "your_target", name = "your_target",
srcs = ["your_source.cc"], srcs = ["your_source.cc"],
deps = [ deps = [
# Choose submodules "@ftxui//:ftxui_component",
"@ftxui//:component", "@ftxui//:ftxui_dom",
"@ftxui//:dom", "@ftxui//:ftxui_screen",
"@ftxui//:screen",
# Or use the single ftxui target (includes all modules)
# "@ftxui//:ftxui",
], ],
) )
``` ```
@@ -447,7 +430,6 @@ If you don't, FTXUI may be used from the following packages:
- [Ubuntu package](https://launchpad.net/ubuntu/+source/ftxui), - [Ubuntu package](https://launchpad.net/ubuntu/+source/ftxui),
- [Arch Linux](https://aur.archlinux.org/packages/ftxui/), - [Arch Linux](https://aur.archlinux.org/packages/ftxui/),
- [OpenSUSE](https://build.opensuse.org/package/show/devel:libraries:c_c++/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) [![Packaging status](https://repology.org/badge/vertical-allrepos/libftxui.svg)](https://repology.org/project/libftxui/versions)

View File

@@ -43,6 +43,16 @@ def windows_copts():
"//conditions:default": [], "//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( def ftxui_cc_library(
name, name,
srcs = [], srcs = [],

View File

@@ -1 +0,0 @@
../../.bazelrc

View File

@@ -1,23 +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.
# Test using individual submodules
cc_binary(
name = "smoke",
srcs = ["smoke.cpp"],
deps = [
"@ftxui//:component",
"@ftxui//:dom",
"@ftxui//:screen",
],
)
# Test using the single ftxui target
cc_binary(
name = "smoke_single_dependency",
srcs = ["smoke.cpp"],
deps = [
"@ftxui",
],
)

View File

@@ -1,9 +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.
module(
name = "ftxui_integration_test",
version = "0.0.1",
)
bazel_dep(name = "ftxui", version = "6.1.9")

View File

@@ -1,38 +0,0 @@
# FTXUI Bazel Integration Test
This directory contains integration tests to verify that FTXUI can be properly consumed as an external dependency using Bazel with Bzlmod.
## Purpose
These tests ensure that:
- FTXUI's public API is correctly exposed to external projects
- Both single-target (`@ftxui//:ftxui`) and submodule-based dependencies work correctly
- Headers are properly re-exported and accessible from downstream projects
## Build Instructions
To build all targets:
```bash
bazel build //... --enable_bzlmod --override_module=ftxui=../..
```
To build individual targets:
```bash
# Test using individual submodules
bazel build //:smoke --enable_bzlmod --override_module=ftxui=../..
# Test using the single ftxui target
bazel build //:smoke_single_dependency --enable_bzlmod --override_module=ftxui=../..
```
## Run the Examples
```bash
# Run the submodules version
./bazel-bin/smoke
# Run the single-target version
./bazel-bin/smoke_single_dependency
```

View File

@@ -1,4 +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.
workspace(name = "ftxui_smoke_test")

View File

@@ -1,16 +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.
#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
int main() {
using namespace ftxui;
auto screen = ScreenInteractive::TerminalOutput();
auto component = Button("Quit", screen.ExitLoopClosure());
screen.Loop(component);
return 0;
}

View File

@@ -13,7 +13,7 @@ include(FetchContent)
FetchContent_Declare(googletest FetchContent_Declare(googletest
GIT_REPOSITORY "https://github.com/google/googletest" GIT_REPOSITORY "https://github.com/google/googletest"
GIT_TAG 52eb8108c5bdec04579160ae17225d66034bd723 # v1.17.0 GIT_TAG 23ef29555ef4789f555f1ba8c51b4c52975f0907
GIT_PROGRESS TRUE GIT_PROGRESS TRUE
) )

View File

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

View File

@@ -6,7 +6,6 @@ add_library(ftxui-modules)
target_sources(ftxui-modules target_sources(ftxui-modules
PUBLIC FILE_SET CXX_MODULES FILES PUBLIC FILE_SET CXX_MODULES FILES
src/ftxui/ftxui.cppm
src/ftxui/component.cppm src/ftxui/component.cppm
src/ftxui/component/animation.cppm src/ftxui/component/animation.cppm
src/ftxui/component/captured_mouse.cppm src/ftxui/component/captured_mouse.cppm

View File

@@ -101,5 +101,6 @@ endfunction()
if (EMSCRIPTEN) if (EMSCRIPTEN)
string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS") 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") string(APPEND CMAKE_EXE_LINKER_FLAGS " -s PROXY_TO_PTHREAD")
endif() endif()

View File

@@ -19,10 +19,11 @@ add_executable(ftxui-tests
src/ftxui/component/menu_test.cpp src/ftxui/component/menu_test.cpp
src/ftxui/component/modal_test.cpp src/ftxui/component/modal_test.cpp
src/ftxui/component/radiobox_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/resizable_split_test.cpp
src/ftxui/component/screen_interactive_test.cpp src/ftxui/component/screen_interactive_test.cpp
src/ftxui/component/slider_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/terminal_input_parser_test.cpp
src/ftxui/component/toggle_test.cpp src/ftxui/component/toggle_test.cpp
src/ftxui/dom/blink_test.cpp src/ftxui/dom/blink_test.cpp
@@ -50,7 +51,6 @@ add_executable(ftxui-tests
src/ftxui/dom/vbox_test.cpp src/ftxui/dom/vbox_test.cpp
src/ftxui/screen/color_test.cpp src/ftxui/screen/color_test.cpp
src/ftxui/screen/string_test.cpp src/ftxui/screen/string_test.cpp
src/ftxui/util/ref_test.cpp
) )
target_link_libraries(ftxui-tests target_link_libraries(ftxui-tests

View File

@@ -1,19 +1,31 @@
@page cpp20-modules C++20 Modules @page cpp20-modules C++20 Modules
coucou
> [!WARNING] > [!WARNING]
> This feature is still in development, and the API may change in future releases. > 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 > Your contribution is needed to help us improve the compatibility and usability
> of C++ modules in FTXUI. If you encounter any issues or have suggestions, > of C++20 modules in FTXUI. If you encounter any issues or have suggestions,
> please open an issue. > please open an issue.
FTXUI experimentally supports FTXUI provides an experimental support for [C++20
[C++20 modules](https://en.cppreference.com/w/cpp/language/modules) to reduce modules](https://en.cppreference.com/w/cpp/language/modules) to improve
compilation times and improve code organization. Each part of the library has a compilation times and code organization. The existing API has a module
corresponding module, split into partitions per each header. corresponding to each header.
Use the FTXUI_BUILD_MODULES option to build the FTXUI project itself to provide C++20 modules, **Example with CMake and Ninja**
for example with CMake and Ninja:
```cpp
import ftxui;
int main() {
auto screen = ftxui::ScreenInteractive::TerminalOutput();
auto button = ftxui::Button("Click me", screen.QuitClosure());
screen.Loop(button);
return 0;
}
```
```sh ```sh
cmake \ cmake \
@@ -23,48 +35,11 @@ cmake \
ninja ninja
``` ```
> [!NOTE] > [!NOTE]
> To use modules, you need a C++20 compatible compiler, CMake version 3.20 or > 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 > higher, and use a compatible generator like Ninja. Note that Makefile
> generators **do not support modules**. > generators **do not support modules**.
Then, in your own code you can consume the modules and code as normal:
```cpp
import ftxui;
using ftxui::Button;
using ftxui::ScreenInteractive;
int main() {
auto screen = ScreenInteractive::TerminalOutput();
auto button = 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 ### Module list
The modules directly reference the corresponding header, or a group of related The modules directly reference the corresponding header, or a group of related
@@ -73,6 +48,38 @@ are available:
- `ftxui` - `ftxui`
- `ftxui.component` - `ftxui.component`
- `ftxui.dom` - `ftxui.component.Animation`
- `ftxui.screen` - `ftxui.component.CapturedMouse`
- `ftxui.util` - `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

@@ -2,9 +2,16 @@
<!-- start footer part --> <!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW--> <!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! --> <div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div> </div>
<!--END GENERATE_TREEVIEW--> <!--END GENERATE_TREEVIEW-->
<!--BEGIN !GENERATE_TREEVIEW--> <!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer"><small>
$generatedby&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion
</small></address>
<!--END !GENERATE_TREEVIEW--> <!--END !GENERATE_TREEVIEW-->
</body> </body>
</html> </html>

View File

@@ -92,24 +92,6 @@
</script> </script>
<script type="module"> <script type="module">
// Ignore non english pages and/or the main page.
const excluded_lang = [
"/de",
"/es",
"/fr",
"/it",
"/ja",
"/ja",
"/ko"
"/ru",
"/zh-CH",
"/zh-TW",
]
if (excluded_lang.some(lang => window.location.pathname.startsWith(lang)) ||
window.location.pathname.endsWith("index.html")) {
return;
}
// Click on the navtree, except for the main page where this is already done // Click on the navtree, except for the main page where this is already done
// automatically. // automatically.
let delay = 0; let delay = 0;

View File

@@ -16,11 +16,6 @@ This page serves as an entry point for the available integration methods.
- @subpage installation_vcpkg - @subpage installation_vcpkg
- @subpage installation_conan - @subpage installation_conan
- @subpage installation_manual - @subpage installation_manual
- @subpage installation_nix
- @subpage installation_debian
- @subpage installation_arch
- @subpage installation_opensuse
- @subpage installation_xmake
## Next Steps ## 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. This approach downloads FTXUI at configure time and doesn't require a system-wide install.
```cmake ```fortran
include(FetchContent) include(FetchContent)
FetchContent_Declare(ftxui 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: If FTXUI is installed system-wide or via a package manager (e.g. vcpkg or Conan), you can use:
```cmake ```fortran
find_package(ftxui REQUIRED) fortranind_package(ftxui REQUIRED)
add_executable(main main.cpp) add_executable(main main.cpp)
target_link_libraries(main 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: 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 add https://github.com/ArthurSonzogni/FTXUI external/ftxui
git submodule update --init --recursive git submodule update --init --recursive
``` ```
@@ -66,7 +66,7 @@ git submodule update --init --recursive
Then in your `CMakeLists.txt`: Then in your `CMakeLists.txt`:
```cmake ```fortran
add_subdirectory(external/ftxui) add_subdirectory(external/ftxui)
add_executable(main main.cpp) add_executable(main main.cpp)

View File

@@ -1,99 +1,15 @@
@page installation_conan Conan @page installation_conan Conan
@tableofcontents @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 ## TODO
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`:
```powershell This page is incomplete. If you use FTXUI with Conan and can provide a minimal working setup, feel free to contribute.
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 中国大陆在这方面的下载可能会受限制,需要一个替代的方案
---
<div class="section_buttons"> <div class="section_buttons">

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 -D FTXUI_ENABLE_INSTALL=ON
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 @page installation_vcpkg Vcpkg
@tableofcontents @tableofcontents
# Vcpkg Package ## Vcpkg Package
FTXUI is available in the [Vcpkg registry](https://vcpkg.link/ports/ftxui) FTXUI is available in the Vcpkg registry:
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
```
- 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"> <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::Render()`: How to render the interface.
- `ftxui::ComponentBase::OnEvent()`: How to react to events. - `ftxui::ComponentBase::OnEvent()`: How to react to events.
- `ftxui::ComponentBase::Add()`: Construct a parent/child relationship - `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. navigate using the keyboard.
`ftxui::Element` are used to render a single frame. `ftxui::Element` are used to render a single frame.
@@ -45,7 +45,7 @@ Produced by: `ftxui::Input()` from "ftxui/component/component.hpp"
## Filtered input ## 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`. `ftxui::CatchEvent`.
```cpp ```cpp
@@ -123,8 +123,8 @@ Produced by: `ftxui::Radiobox()` from "ftxui/component/component.hpp"
# Dropdown {#component-dropdown} # Dropdown {#component-dropdown}
A drop-down menu is a component that, when opened, displays a list of elements A drop down menu is a component that when checked display a list of element for
for the user to select from. the user to select one.
[Example](https://arthursonzogni.github.io/FTXUI/examples_2component_2dropdown_8cpp-example.html): [Example](https://arthursonzogni.github.io/FTXUI/examples_2component_2dropdown_8cpp-example.html):
@@ -204,12 +204,12 @@ component = component
# Collapsible {#component-collapsible} # Collapsible {#component-collapsible}
Useful for visual elements whose visibility can be toggled on or off by the Useful for visual elements whose visibility can be toggle on/off by the user.
user. Essentially, this is the combination of the `ftxui::Checkbox()` and Essentially, this the combination of the `ftxui::Checkbox()` and
`ftxui::Maybe()` components. `ftxui::Maybe()` components.
```cpp ```cpp
auto collapsible = Collapsible("Show more", inner_element); auto collabsible = Collapsible("Show more", inner_element);
``` ```
# Maybe {#component-maybe} # Maybe {#component-maybe}
@@ -245,7 +245,7 @@ component = component
Produced by: `ftxui::Container::Horizontal()` from Produced by: `ftxui::Container::Horizontal()` from
"ftxui/component/component.hpp". It displays a list of components horizontally "ftxui/component/component.hpp". It displays a list of components horizontally
and handles keyboard/mouse navigation. and handle keyboard/mouse navigation.
## Vertical {#component-vertical} ## Vertical {#component-vertical}
@@ -256,8 +256,8 @@ and handles keyboard/mouse navigation.
## Tab {#component-tab} ## Tab {#component-tab}
Produced by: `ftxui::Container::Tab()` from Produced by: `ftxui::Container::Tab()` from
"ftxui/component/component.hpp". It takes a list of components and displays "ftxui/component/component.hpp". It take a list of component and display only
only one of them. This is useful for implementing a tab bar. one of them. This is useful for implementing a tab bar.
[Vertical](https://arthursonzogni.github.io/FTXUI/examples_2component_2tab_vertical_8cpp-example.html): [Vertical](https://arthursonzogni.github.io/FTXUI/examples_2component_2tab_vertical_8cpp-example.html):

View File

@@ -207,7 +207,7 @@ Code:
border(gauge(0.5)) border(gauge(0.5))
``` ```
Terminal output: Teminal output:
```bash ```bash
┌────────────────────────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────────────────────────┐
│██████████████████████████████████████ │ │██████████████████████████████████████ │
@@ -407,7 +407,7 @@ Checkout this
and the associated and the associated
[demo](https://arthursonzogni.github.io/FTXUI/examples/?file=component/flexbox). [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: Code:
```cpp ```cpp

View File

@@ -1,58 +0,0 @@
# POSIX Piped Input in FTXUI
> [!WARNING]
> This feature works only on Linux and macOS. It is not supported on
> Windows and WebAssembly.
## What is a POSIX Pipe?
A POSIX pipe is a way for two separate programs to communicate. One program sends its output directly as input to another program. Think of it like a one-way tube for data.
**Example:**
Imagine you want to list files and then filter them interactively.
- `ls`: Lists files.
- `interactive_grep`: An FTXUI application that filters text and lets you type.
You can connect them with a pipe (`|`):
```bash
ls -l | interactive_grep
```
Here's what happens:
1. `ls -l` lists files with details.
2. The `|` sends this list directly to `interactive_grep`.
3. `interactive_grep` receives the list and displays it. Because it's an FTXUI app, you can then type to filter the list, even though it received initial data from `ls`.
## How FTXUI Handles Piped Input
Now that you understand what a POSIX pipe is, let's look at how FTXUI uses them.
FTXUI lets your application read data from other programs (like from a pipe) while still allowing you to use your keyboard for interaction. This is useful for interactive command-line tools that process data.
Normally, FTXUI applications receive all input from `stdin`. However, when FTXUI detects that `stdin` is connected to the output of a pipe (meaning data is being piped into your application), it automatically switches to reading interactive keyboard input from `/dev/tty`. This ensures that your application can still receive user input even while processing piped data.
This feature is **turned on by default**.
If your FTXUI application needs to read piped data and also respond to keyboard input, you typically don't need to do anything special:
```cpp
auto screen = ScreenInteractive::Fullscreen();
// screen.HandlePipedInput(true); // This is enabled by default
screen.Loop(component);
```
## Turning Off Piped Input
If you don't need this feature, or if it conflicts with your custom input handling, you can turn it off.
To disable it, call `HandlePipedInput(false)` before starting your application's main loop:
```cpp
auto screen = ScreenInteractive::Fullscreen();
screen.HandlePipedInput(false); // Turn off piped input handling
screen.Loop(component);
```

View File

@@ -15,14 +15,16 @@ add_subdirectory(component)
add_subdirectory(dom) add_subdirectory(dom)
if (EMSCRIPTEN) 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) get_property(EXAMPLES GLOBAL PROPERTY FTXUI::EXAMPLES)
foreach(file foreach(file
"index.css"
"index.html" "index.html"
"index.mjs" "index.mjs"
"run_webassembly.py" "index.css"
"sw.js" "sw.js"
) "run_webassembly.py")
configure_file(${file} ${file}) configure_file(${file} ${file})
endforeach(file) endforeach(file)
endif() endif()

View File

@@ -39,7 +39,6 @@ example(radiobox)
example(radiobox_in_frame) example(radiobox_in_frame)
example(renderer) example(renderer)
example(resizable_split) example(resizable_split)
example(resizable_split_clamp)
example(scrollbar) example(scrollbar)
example(selection) example(selection)
example(slider) example(slider)

View File

@@ -1,64 +1,9 @@
// Copyright 2020 Arthur Sonzogni. All rights reserved. #include "ftxui/component/component.hpp"
// Use of this source code is governed by the MIT license that can be found in #include "ftxui/component/screen_interactive.hpp"
// the LICENSE file.
#include <memory> // for shared_ptr, __shared_ptr_access
#include <string> // for operator+, to_string
#include "ftxui/component/captured_mouse.hpp" // for ftxui int main(){
#include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer auto screen = ftxui::ScreenInteractive::Fullscreen();
#include "ftxui/component/component_base.hpp" // for ComponentBase auto testComponent = ftxui::Renderer([](){return ftxui::text("test Component");});
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive screen.Loop(testComponent);
#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; return 0;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,9 +17,8 @@ int main() {
std::vector<std::string> entries; std::vector<std::string> entries;
int selected = 0; int selected = 0;
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i)
entries.push_back(std::to_string(i)); entries.push_back(std::to_string(i));
}
auto radiobox = Menu(&entries, &selected, MenuOption::Horizontal()); auto radiobox = Menu(&entries, &selected, MenuOption::Horizontal());
auto renderer = Renderer( auto renderer = Renderer(
radiobox, [&] { return radiobox->Render() | hscroll_indicator | frame; }); 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) { option.entries_option.transform = [](EntryState state) {
state.label = (state.active ? "> " : " ") + state.label; state.label = (state.active ? "> " : " ") + state.label;
Element e = text(state.label); Element e = text(state.label);
if (state.focused) { if (state.focused)
e = e | bgcolor(Color::Blue); e = e | bgcolor(Color::Blue);
} if (state.active)
if (state.active) {
e = e | bold; e = e | bold;
}
return e; return e;
}; };
return Menu(entries, selected, option); return Menu(entries, selected, option);
@@ -132,12 +130,10 @@ Component VMenu2(std::vector<std::string>* entries, int* selected) {
option.entries_option.transform = [](EntryState state) { option.entries_option.transform = [](EntryState state) {
state.label += (state.active ? " <" : " "); state.label += (state.active ? " <" : " ");
Element e = hbox(filler(), text(state.label)); Element e = hbox(filler(), text(state.label));
if (state.focused) { if (state.focused)
e = e | bgcolor(Color::Red); e = e | bgcolor(Color::Red);
} if (state.active)
if (state.active) {
e = e | bold; e = e | bold;
}
return e; return e;
}; };
return Menu(entries, selected, option); return Menu(entries, selected, option);
@@ -148,16 +144,13 @@ Component VMenu3(std::vector<std::string>* entries, int* selected) {
option.entries_option.transform = [](EntryState state) { option.entries_option.transform = [](EntryState state) {
Element e = state.active ? text("[" + state.label + "]") Element e = state.active ? text("[" + state.label + "]")
: text(" " + state.label + " "); : text(" " + state.label + " ");
if (state.focused) { if (state.focused)
e = e | bold; e = e | bold;
}
if (state.focused) { if (state.focused)
e = e | color(Color::Blue); e = e | color(Color::Blue);
} if (state.active)
if (state.active) {
e = e | bold; e = e | bold;
}
return e; return e;
}; };
return Menu(entries, selected, option); return Menu(entries, selected, option);
@@ -252,12 +245,10 @@ Component HMenu5(std::vector<std::string>* entries, int* selected) {
animation::easing::ElasticOut); animation::easing::ElasticOut);
option.entries_option.transform = [](EntryState state) { option.entries_option.transform = [](EntryState state) {
Element e = text(state.label) | hcenter | flex; Element e = text(state.label) | hcenter | flex;
if (state.active && state.focused) { if (state.active && state.focused)
e = e | bold; e = e | bold;
} if (!state.focused && !state.active)
if (!state.focused && !state.active) {
e = e | dim; e = e | dim;
}
return e; return e;
}; };
option.underline.color_inactive = Color::Default; option.underline.color_inactive = Color::Default;

View File

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

View File

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

View File

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

View File

@@ -3,6 +3,7 @@
// the LICENSE file. // the LICENSE file.
#include <memory> // for shared_ptr, allocator, __shared_ptr_access #include <memory> // for shared_ptr, allocator, __shared_ptr_access
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop #include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
@@ -13,24 +14,17 @@ using namespace ftxui;
int main() { int main() {
auto screen = ScreenInteractive::Fullscreen(); auto screen = ScreenInteractive::Fullscreen();
// State: auto middle = Renderer([] { return text("middle") | center; });
auto left = Renderer([] { return text("Left") | center; });
auto right = Renderer([] { return text("right") | center; });
auto top = Renderer([] { return text("top") | center; });
auto bottom = Renderer([] { return text("bottom") | center; });
int left_size = 20; int left_size = 20;
int right_size = 20; int right_size = 20;
int top_size = 10; int top_size = 10;
int bottom_size = 10; int bottom_size = 10;
// Renderers:
auto RendererInfo = [](const std::string& name, int* size) {
return Renderer([name, size] {
return text(name + ": " + std::to_string(*size)) | center;
});
};
auto middle = Renderer([] { return text("Middle") | center; });
auto left = RendererInfo("Left", &left_size);
auto right = RendererInfo("Right", &right_size);
auto top = RendererInfo("Top", &top_size);
auto bottom = RendererInfo("Bottom", &bottom_size);
auto container = middle; auto container = middle;
container = ResizableSplitLeft(left, container, &left_size); container = ResizableSplitLeft(left, container, &left_size);
container = ResizableSplitRight(right, container, &right_size); container = ResizableSplitRight(right, container, &right_size);

View File

@@ -1,43 +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.
#include <memory> // for shared_ptr, allocator, __shared_ptr_access
#include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for Element, operator|, text, center, border
using namespace ftxui;
int main() {
auto screen = ScreenInteractive::Fullscreen();
// State:
int size = 40;
int size_min = 10;
int size_max = 80;
// Renderers:
auto split = ResizableSplit({
.main = Renderer([] { return text("Left") | center; }),
.back = Renderer([] { return text("Right") | center; }),
.direction = Direction::Left,
.main_size = &size,
.min = &size_min,
.max = &size_max,
});
auto renderer = Renderer(split, [&] {
return window(text("Drag the separator with the mouse"),
vbox({
text("Min: " + std::to_string(size_min)),
text("Max: " + std::to_string(size_max)),
text("Size: " + std::to_string(size)),
separator(),
split->Render() | flex,
}));
});
screen.Loop(renderer);
}

View File

@@ -32,12 +32,10 @@ int main() {
// Plot a function: // Plot a function:
std::vector<int> ys(100); 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)); 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); c.DrawPointLine(x, ys[x], x + 1, ys[x + 1], Color::Red);
}
auto document = canvas(&c) | border; auto document = canvas(&c) | border;

View File

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

View File

@@ -21,9 +21,8 @@ int main() {
for (int index = 0; index < 200; ++index) { for (int index = 0; index < 200; ++index) {
std::vector<Element> entries; std::vector<Element> entries;
for (int i = 0; i < 23; ++i) { for (int i = 0; i < 23; ++i) {
if (i != 0) { if (i != 0)
entries.push_back(separator()); entries.push_back(separator());
}
entries.push_back( // entries.push_back( //
hbox({ hbox({
text(std::to_string(i)) | size(WIDTH, EQUAL, 2), 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); @import url(https://fonts.googleapis.com/css?family=Khula:700);
html {
--toc-width: 250px;
}
body { body {
background-color: #EEE; background-color:#EEE;
padding: 0px; padding:0px;
margin: 0px; margin:0px;
font-family: Khula, Helvetica, sans-serif; font-family: Khula, Helvetica, sans-serif;
font-size: 130%; font-size: 130%;
} }
.page { .page {
max-width: 1300px; max-width:1300px;
margin: auto; margin: auto;
padding: 10px; padding: 10px;
} }
@@ -34,48 +30,45 @@ a:hover {
h1 { h1 {
text-decoration: underline; text-decoration: underline;
width: 100%; width:100%;
background-color: rgba(100, 100, 255, 0.5); background-color: rgba(100,100,255,0.5);
padding: 10px; padding: 10px;
margin: 0; margin: 0;
} }
#selectExample { #selectExample {
flex: 1; flex:1;
} }
#selectExample, #selectExample, #selectExample option {
#selectExample option {
font-size: 16px; font-size: 16px;
font-family: sans-serif; font-family: sans-serif;
font-weight: 700; font-weight: 700;
line-height: 1.3; line-height: 1.3;
border: 0px; border:0px;
background-color: #bbb; background-color: #bbb;
color: black; color:black;
} }
#selectExample:focus { #selectExample:focus {
outline: none; outline:none;
} }
#terminal { #terminal {
width: 100%; width:100%;
height 500px; height 500px;
height: calc(clamp(200px, 100vh - 300px, 900px)); height: calc(clamp(200px, 100vh - 300px, 900px));
overflow: hidden; overflow: hidden;
border: none; border:none;
padding: 10px; background-color:black;
margin: 10px;
} }
#terminalContainer { #terminalContainer {
overflow: hidden; overflow: hidden;
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.75), box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.75),
0px 2px 80px 0px rgba(0, 0, 0, 0.50); 0px 2px 80px 0px rgba(0,0,0,0.50);
background-color: black;
} }
.fakeButtons { .fakeButtons {
@@ -83,7 +76,7 @@ h1 {
width: 10px; width: 10px;
border-radius: 50%; border-radius: 50%;
border: 1px solid #000; border: 1px solid #000;
margin: 6px; margin:6px;
background-color: #ff3b47; background-color: #ff3b47;
border-color: #9d252b; border-color: #9d252b;
display: inline-block; display: inline-block;
@@ -102,79 +95,13 @@ h1 {
} }
.fakeMenu { .fakeMenu {
display: flex; display:flex;
flex-direction: row; flex-direction: row;
width: 100%; width:100%;
box-sizing: border-box; box-sizing: border-box;
height: 25px; height: 25px;
background-color: #bbb; background-color: #bbb;
color: black; color:black;
margin: 0 auto; margin: 0 auto;
overflow: hidden; 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> <script type="module" src="index.mjs"></script>
</head> </head>
<body> <body>
<div class="toc-container">
<div class="toc-list"></div>
</div>
<script id="example_script"></script> <script id="example_script"></script>
<div class="page"> <div class="page">
<p> <p>
<a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a simple <a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a simple
functional C++ library for terminal user interface. <br/> functional C++ library for terminal user interface. <br/>
This showcases the: <a This showcases the: <a href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a> folder. <br/>
href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a>
folder. See <a id="source">source</a>.
</p> </p>
<div id="terminalContainer"> <div id="terminalContainer">

View File

@@ -55,7 +55,7 @@ const stdout = code => {
const stderr = code => { const stderr = code => {
if (code == 0 || code == 10) { if (code == 0 || code == 10) {
console.error(String.fromCodePoint(...stderr_buffer)); console.error(String.fromCodePoint(...stderr_buffer));
stderr_buffer.length = 0; stderr_buffer = [];
} else { } else {
stderr_buffer.push(code) stderr_buffer.push(code)
} }
@@ -89,72 +89,12 @@ window.Module = {
const resize_observer = new ResizeObserver(resize_handler); const resize_observer = new ResizeObserver(resize_handler);
resize_observer.observe(term_element); resize_observer.observe(term_element);
resize_handler(); 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('/') const words = example.split('/')
words[1] = "ftxui_example_" + words[1] + ".js" words[1] = "ftxui_example_" + words[1] + ".js"
document.querySelector("#example_script").src = words.join('/'); 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);
}
}''

12
flake.lock generated
View File

@@ -5,11 +5,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1694529238,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1765644376, "lastModified": 1697915759,
"narHash": "sha256-yqHBL2wYGwjGL2GUF2w3tofWl8qO9tZEuI4wSqbCrtE=", "narHash": "sha256-WyMj5jGcecD+KC8gEs+wFth1J1wjisZf8kVZH13f1Zo=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "23735a82a828372c4ef92c660864e82fbe2f5fbe", "rev": "51d906d2341c9e866e48c2efcaac0f2d70bfd43e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -12,9 +12,15 @@
let llvm = pkgs.llvmPackages_latest; in let llvm = pkgs.llvmPackages_latest; in
{ {
packages = rec { packages = rec {
default = pkgs.stdenv.mkDerivation { default = pkgs.stdenv.mkDerivation rec {
name = "ftxui"; pname = "ftxui";
src = ./.; version = "v4.0.0";
src = pkgs.fetchFromGitHub {
owner = "ArthurSonzogni";
repo = "FTXUI";
rev = version;
sha256 = "sha256-3kAhHDUwzwdvHc8JZAcA14tGqa6w69qrN1JXhSxNBQY=";
};
nativeBuildInputs = [ nativeBuildInputs = [
pkgs.cmake pkgs.cmake

View File

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

View File

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

View File

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

View File

@@ -9,9 +9,7 @@
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Left, Direction::Right, Direction::Down #include <ftxui/dom/direction.hpp> // for Direction, Direction::Left, Direction::Right, Direction::Down
#include <ftxui/dom/elements.hpp> // for Element, separator #include <ftxui/dom/elements.hpp> // for Element, separator
#include <ftxui/util/ref.hpp> // for Ref, ConstRef, StringRef #include <ftxui/util/ref.hpp> // for Ref, ConstRef, StringRef
#include <ftxui/util/warn_windows_macro.hpp>
#include <functional> // for function #include <functional> // for function
#include <limits> // for numeric_limits
#include <string> // for string #include <string> // for string
#include "ftxui/component/component_base.hpp" // for Component #include "ftxui/component/component_base.hpp" // for Component
@@ -29,8 +27,6 @@ struct EntryState {
int index; ///< Index of the entry when applicable or -1. int index; ///< Index of the entry when applicable or -1.
}; };
/// @brief Option for the underline effect.
/// @ingroup component
struct UnderlineOption { struct UnderlineOption {
bool enabled = false; bool enabled = false;
@@ -218,10 +214,6 @@ struct ResizableSplitOption {
(direction() == Direction::Left || direction() == Direction::Right) ? 20 (direction() == Direction::Left || direction() == Direction::Right) ? 20
: 10; : 10;
std::function<Element()> separator_func = [] { return ::ftxui::separator(); }; std::function<Element()> separator_func = [] { return ::ftxui::separator(); };
// Constraints on main_size:
Ref<int> min = 0;
Ref<int> max = std::numeric_limits<int>::max();
}; };
// @brief Option for the `Slider` component. // @brief Option for the `Slider` component.
@@ -238,8 +230,7 @@ struct SliderOption {
std::function<void()> on_change; ///> Called when `value` is updated. std::function<void()> on_change; ///> Called when `value` is updated.
}; };
/// @brief State passed to the `Window` component's render function. // Parameter pack used by `WindowOptions::render`.
/// @ingroup component
struct WindowRenderState { struct WindowRenderState {
Element inner; ///< The element wrapped inside this window. Element inner; ///< The element wrapped inside this window.
const std::string& title; ///< The title of the window. const std::string& title; ///< The title of the window.

View File

@@ -6,7 +6,6 @@
#include <ftxui/component/mouse.hpp> // for Mouse #include <ftxui/component/mouse.hpp> // for Mouse
#include <string> // for string, operator== #include <string> // for string, operator==
#include <string_view>
namespace ftxui { namespace ftxui {
@@ -25,17 +24,15 @@ class ComponentBase;
/// ///
/// Useful documentation about xterm specification: /// Useful documentation about xterm specification:
/// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html /// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
///
/// @ingroup component
struct Event { struct Event {
// --- Constructor section --------------------------------------------------- // --- Constructor section ---------------------------------------------------
static Event Character(std::string_view); static Event Character(std::string);
static Event Character(char); static Event Character(char);
static Event Character(wchar_t); static Event Character(wchar_t);
static Event Special(std::string_view); static Event Special(std::string);
static Event Mouse(std::string_view, Mouse mouse); static Event Mouse(std::string, Mouse mouse);
static Event CursorPosition(std::string_view, int x, int y); // Internal static Event CursorPosition(std::string, int x, int y); // Internal
static Event CursorShape(std::string_view, int shape); // Internal static Event CursorShape(std::string, int shape); // Internal
// --- Arrow --- // --- Arrow ---
static const Event ArrowLeft; static const Event ArrowLeft;

View File

@@ -14,45 +14,6 @@ class ComponentBase;
using Component = std::shared_ptr<ComponentBase>; using Component = std::shared_ptr<ComponentBase>;
class ScreenInteractive; 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 { class Loop {
public: public:
Loop(ScreenInteractive* screen, Component component); Loop(ScreenInteractive* screen, Component component);

View File

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

View File

@@ -5,9 +5,12 @@
#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#include <atomic> // for atomic #include <atomic> // for atomic
#include <ftxui/component/receiver.hpp> // for Receiver, Sender
#include <functional> // for function #include <functional> // for function
#include <memory> // for shared_ptr #include <memory> // for shared_ptr
#include <string> // for string #include <string> // for string
#include <thread> // for thread
#include <variant> // for variant
#include "ftxui/component/animation.hpp" // for TimePoint #include "ftxui/component/animation.hpp" // for TimePoint
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
@@ -24,14 +27,6 @@ struct Event;
using Component = std::shared_ptr<ComponentBase>; using Component = std::shared_ptr<ComponentBase>;
class ScreenInteractivePrivate; 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 { class ScreenInteractive : public Screen {
public: public:
// Constructors: // Constructors:
@@ -42,12 +37,8 @@ class ScreenInteractive : public Screen {
static ScreenInteractive FitComponent(); static ScreenInteractive FitComponent();
static ScreenInteractive TerminalOutput(); static ScreenInteractive TerminalOutput();
// Destructor.
~ScreenInteractive() override;
// Options. Must be called before Loop(). // Options. Must be called before Loop().
void TrackMouse(bool enable = true); void TrackMouse(bool enable = true);
void HandlePipedInput(bool enable = true);
// Return the currently active screen, nullptr if none. // Return the currently active screen, nullptr if none.
static ScreenInteractive* Active(); static ScreenInteractive* Active();
@@ -101,14 +92,8 @@ class ScreenInteractive : public Screen {
void Draw(Component component); void Draw(Component component);
void ResetCursorPosition(); void ResetCursorPosition();
void InstallPipedInputHandling();
void Signal(int signal); void Signal(int signal);
void FetchTerminalEvents();
void PostAnimationTask();
ScreenInteractive* suspended_screen_ = nullptr; ScreenInteractive* suspended_screen_ = nullptr;
enum class Dimension { enum class Dimension {
FitComponent, FitComponent,
@@ -116,27 +101,30 @@ class ScreenInteractive : public Screen {
Fullscreen, Fullscreen,
TerminalOutput, TerminalOutput,
}; };
ScreenInteractive(Dimension dimension, Dimension dimension_ = Dimension::Fixed;
int dimx, bool use_alternative_screen_ = false;
ScreenInteractive(int dimx,
int dimy, int dimy,
Dimension dimension,
bool use_alternative_screen); bool use_alternative_screen);
const Dimension dimension_;
const bool use_alternative_screen_;
bool track_mouse_ = true; bool track_mouse_ = true;
Sender<Task> task_sender_;
Receiver<Task> task_receiver_;
std::string set_cursor_position; std::string set_cursor_position;
std::string reset_cursor_position; std::string reset_cursor_position;
std::atomic<bool> quit_{false}; std::atomic<bool> quit_{false};
std::thread event_listener_;
std::thread animation_listener_;
bool animation_requested_ = false; bool animation_requested_ = false;
animation::TimePoint previous_animation_time_; animation::TimePoint previous_animation_time_;
int cursor_x_ = 1; int cursor_x_ = 1;
int cursor_y_ = 1; int cursor_y_ = 1;
std::uint64_t frame_count_ = 0;
bool mouse_captured = false; bool mouse_captured = false;
bool previous_frame_resized_ = false; bool previous_frame_resized_ = false;
@@ -145,11 +133,6 @@ class ScreenInteractive : public Screen {
bool force_handle_ctrl_c_ = true; bool force_handle_ctrl_c_ = true;
bool force_handle_ctrl_z_ = true; bool force_handle_ctrl_z_ = true;
// Piped input handling state (POSIX only)
bool handle_piped_input_ = true;
// File descriptor for /dev/tty, used for piped input handling.
int tty_fd_ = -1;
// The style of the cursor to restore on exit. // The style of the cursor to restore on exit.
int cursor_reset_shape_ = 1; int cursor_reset_shape_ = 1;
@@ -169,14 +152,8 @@ class ScreenInteractive : public Screen {
std::unique_ptr<Selection> selection_; std::unique_ptr<Selection> selection_;
std::function<void()> selection_on_change_; std::function<void()> selection_on_change_;
// PIMPL private implementation idiom (Pimpl).
struct Internal;
std::unique_ptr<Internal> internal_;
friend class Loop; friend class Loop;
Component component_;
public: public:
class Private { class Private {
public: public:

View File

@@ -20,21 +20,6 @@
namespace ftxui { 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 { struct Canvas {
public: public:
Canvas() = default; Canvas() = default;
@@ -106,9 +91,9 @@ struct Canvas {
// Draw using character of size 2x4 at position (x,y) // Draw using character of size 2x4 at position (x,y)
// x is considered to be a multiple of 2. // x is considered to be a multiple of 2.
// y is considered to be a multiple of 4. // y is considered to be a multiple of 4.
void DrawText(int x, int y, std::string_view value); void DrawText(int x, int y, const std::string& value);
void DrawText(int x, int y, std::string_view value, const Color& color); void DrawText(int x, int y, const std::string& value, const Color& color);
void DrawText(int x, int y, std::string_view value, const Stylizer& style); void DrawText(int x, int y, const std::string& value, const Stylizer& style);
// Draw using directly pixels or images -------------------------------------- // Draw using directly pixels or images --------------------------------------
// x is considered to be a multiple of 2. // x is considered to be a multiple of 2.

View File

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

View File

@@ -7,7 +7,6 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string_view>
#include "ftxui/dom/canvas.hpp" #include "ftxui/dom/canvas.hpp"
#include "ftxui/dom/direction.hpp" #include "ftxui/dom/direction.hpp"
#include "ftxui/dom/flexbox_config.hpp" #include "ftxui/dom/flexbox_config.hpp"
@@ -25,14 +24,6 @@ using Elements = std::vector<Element>;
using Decorator = std::function<Element(Element)>; using Decorator = std::function<Element(Element)>;
using GraphFunction = std::function<std::vector<int>(int, int)>; 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 { enum BorderStyle {
LIGHT, LIGHT,
DASHED, DASHED,
@@ -52,8 +43,8 @@ Elements operator|(Elements, Decorator);
Decorator operator|(Decorator, Decorator); Decorator operator|(Decorator, Decorator);
// --- Widget --- // --- Widget ---
Element text(std::string_view text); Element text(std::string text);
Element vtext(std::string_view text); Element vtext(std::string text);
Element separator(); Element separator();
Element separatorLight(); Element separatorLight();
Element separatorDashed(); Element separatorDashed();
@@ -62,7 +53,7 @@ Element separatorDouble();
Element separatorEmpty(); Element separatorEmpty();
Element separatorStyled(BorderStyle); Element separatorStyled(BorderStyle);
Element separator(Pixel); Element separator(Pixel);
Element separatorCharacter(std::string_view); Element separatorCharacter(std::string);
Element separatorHSelector(float left, Element separatorHSelector(float left,
float right, float right,
Color unselected_color, Color unselected_color,
@@ -90,11 +81,11 @@ Decorator borderStyled(Color);
Decorator borderWith(const Pixel&); Decorator borderWith(const Pixel&);
Element window(Element title, Element content, BorderStyle border = ROUNDED); Element window(Element title, Element content, BorderStyle border = ROUNDED);
Element spinner(int charset_index, size_t image_index); Element spinner(int charset_index, size_t image_index);
Element paragraph(std::string_view text); Element paragraph(const std::string& text);
Element paragraphAlignLeft(std::string_view text); Element paragraphAlignLeft(const std::string& text);
Element paragraphAlignRight(std::string_view text); Element paragraphAlignRight(const std::string& text);
Element paragraphAlignCenter(std::string_view text); Element paragraphAlignCenter(const std::string& text);
Element paragraphAlignJustify(std::string_view text); Element paragraphAlignJustify(const std::string& text);
Element graph(GraphFunction); Element graph(GraphFunction);
Element emptyElement(); Element emptyElement();
Element canvas(ConstRef<Canvas>); Element canvas(ConstRef<Canvas>);
@@ -121,8 +112,8 @@ Element bgcolor(const LinearGradient&, Element);
Decorator focusPosition(int x, int y); Decorator focusPosition(int x, int y);
Decorator focusPositionRelative(float x, float y); Decorator focusPositionRelative(float x, float y);
Element automerge(Element child); Element automerge(Element child);
Decorator hyperlink(std::string_view link); Decorator hyperlink(std::string link);
Element hyperlink(std::string_view link, Element child); Element hyperlink(std::string link, Element child);
Element selectionStyleReset(Element); Element selectionStyleReset(Element);
Decorator selectionColor(Color foreground); Decorator selectionColor(Color foreground);
Decorator selectionBackgroundColor(Color foreground); Decorator selectionBackgroundColor(Color foreground);

View File

@@ -12,18 +12,6 @@
namespace ftxui { 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 { struct FlexboxConfig {
/// This establishes the main-axis, thus defining the direction flex items are /// This establishes the main-axis, thus defining the direction flex items are
/// placed in the flex container. Flexbox is (aside wrapping) single-direction /// 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(Color::Red, Color::Blue);
/// LinearGradient(45, Color::Red, Color::Blue); /// LinearGradient(45, Color::Red, Color::Blue);
/// ``` /// ```
///
/// @ingroup dom
struct LinearGradient { struct LinearGradient {
float angle = 0.f; 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 { struct Stop {
Color color = Color::Default; Color color = Color::Default;
std::optional<float> position; std::optional<float> position;

View File

@@ -20,20 +20,6 @@ class Screen;
using Element = std::shared_ptr<Node>; using Element = std::shared_ptr<Node>;
using Elements = std::vector<Element>; 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 { class Node {
public: public:
Node(); Node();

View File

@@ -10,11 +10,6 @@
namespace ftxui { namespace ftxui {
class Node; 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 { struct Requirement {
// The required size to fully draw the element. // The required size to fully draw the element.
int min_x = 0; int min_x = 0;

View File

@@ -13,12 +13,7 @@
namespace ftxui { namespace ftxui {
/// @brief Represents a selection in a terminal user interface. /// @brief Represent a selection in the terminal.
///
/// Selection is a class that represents the two endpoints of a selection in a
/// terminal user interface.
///
/// @ingroup dom
class Selection { class Selection {
public: public:
Selection(); // Empty selection. Selection(); // Empty selection.
@@ -30,7 +25,7 @@ class Selection {
Selection SaturateVertical(Box box); Selection SaturateVertical(Box box);
bool IsEmpty() const { return empty_; } bool IsEmpty() const { return empty_; }
void AddPart(std::string_view part, int y, int left, int right); void AddPart(const std::string& part, int y, int left, int right);
std::string GetParts() { return parts_.str(); } std::string GetParts() { return parts_.str(); }
private: private:

View File

@@ -11,28 +11,28 @@
namespace ftxui { 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 Table;
class TableSelection; 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 { class Table {
public: public:
Table(); Table();

View File

@@ -5,18 +5,25 @@
#define FTXUI_DOM_TAKE_ANY_ARGS_HPP #define FTXUI_DOM_TAKE_ANY_ARGS_HPP
// IWYU pragma: private, include "ftxui/dom/elements.hpp" // IWYU pragma: private, include "ftxui/dom/elements.hpp"
#include <deque>
#include <ftxui/dom/node.hpp> #include <ftxui/dom/node.hpp>
#include <queue>
#include <stack>
#include <vector>
namespace ftxui { namespace ftxui {
template <class T>
void Merge(Elements& /*container*/, T /*element*/) {}
template <>
inline void Merge(Elements& container, Element element) { inline void Merge(Elements& container, Element element) {
container.push_back(std::move(element)); container.push_back(std::move(element));
} }
template <>
inline void Merge(Elements& container, Elements elements) {
for (auto& element : elements) {
container.push_back(std::move(element));
}
}
// Turn a set of arguments into a vector. // Turn a set of arguments into a vector.
template <class... Args> template <class... Args>
Elements unpack(Args... args) { Elements unpack(Args... args) {
@@ -25,50 +32,11 @@ Elements unpack(Args... args) {
return vec; return vec;
} }
// Make |container| able to take any number of arguments. // Make |container| able to take any number of argments.
#define TAKE_ANY_ARGS(container) \ #define TAKE_ANY_ARGS(container) \
inline Element container(Element child) { \
return container(unpack(std::move(child))); \
} \
\
template <class... Args> \ template <class... Args> \
inline Element container(Args... children) { \ Element container(Args... children) { \
return container(unpack(std::forward<Args>(children)...)); \ return container(unpack(std::forward<Args>(children)...)); \
} \
\
template <class Container> \
inline Element container(Container&& children) { \
Elements elements; \
for (auto& child : children) { \
elements.push_back(std::move(child)); \
} \
return container(std::move(elements)); \
} \
template <> \
inline Element container(std::stack<Element>&& children) { \
Elements elements; \
while (!children.empty()) { \
elements.push_back(std::move(children.top())); \
children.pop(); \
} \
return container(std::move(elements)); \
} \
template <> \
inline Element container(std::queue<Element>&& children) { \
Elements elements; \
while (!children.empty()) { \
elements.push_back(std::move(children.front())); \
children.pop(); \
} \
return container(std::move(elements)); \
} \
template <> \
inline Element container(std::deque<Element>&& children) { \
Elements elements; \
for (auto& child : children) { \
elements.push_back(std::move(child)); \
} \
return container(std::move(elements)); \
} }
TAKE_ANY_ARGS(vbox) TAKE_ANY_ARGS(vbox)

View File

@@ -6,13 +6,6 @@
namespace ftxui { 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 { struct Box {
int x_min = 0; int x_min = 0;
int x_max = 0; int x_max = 0;

View File

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

View File

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

View File

@@ -20,9 +20,6 @@ class Image {
Image() = delete; Image() = delete;
Image(int dimx, int dimy); Image(int dimx, int dimy);
// Destructor:
virtual ~Image() = default;
// Access a character in the grid at a given position. // Access a character in the grid at a given position.
std::string& at(int x, int y); std::string& at(int x, int y);
const std::string& at(int x, int y) const; 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/image.hpp" // for Pixel, Image
#include "ftxui/screen/terminal.hpp" // for Dimensions #include "ftxui/screen/terminal.hpp" // for Dimensions
#include "ftxui/util/autoreset.hpp" // for AutoReset
namespace ftxui { namespace ftxui {
@@ -30,9 +31,6 @@ class Screen : public Image {
static Screen Create(Dimensions dimension); static Screen Create(Dimensions dimension);
static Screen Create(Dimensions width, Dimensions height); static Screen Create(Dimensions width, Dimensions height);
// Destructor:
~Screen() override = default;
std::string ToString() const; std::string ToString() const;
// Print the Screen on to the terminal. // Print the Screen on to the terminal.
@@ -60,7 +58,7 @@ class Screen : public Image {
BarBlinking = 5, BarBlinking = 5,
Bar = 6, Bar = 6,
}; };
Shape shape = Hidden; Shape shape;
}; };
Cursor cursor() const { return cursor_; } Cursor cursor() const { return cursor_; }
@@ -68,7 +66,7 @@ class Screen : public Image {
// Store an hyperlink in the screen. Return the id of the hyperlink. The id is // Store an hyperlink in the screen. Return the id of the hyperlink. The id is
// used to identify the hyperlink when the user click on it. // used to identify the hyperlink when the user click on it.
uint8_t RegisterHyperlink(std::string_view link); uint8_t RegisterHyperlink(const std::string& link);
const std::string& Hyperlink(uint8_t id) const; const std::string& Hyperlink(uint8_t id) const;
using SelectionStyle = std::function<void(Pixel&)>; using SelectionStyle = std::function<void(Pixel&)>;

View File

@@ -5,31 +5,26 @@
#define FTXUI_SCREEN_STRING_HPP #define FTXUI_SCREEN_STRING_HPP
#include <string> // for string, wstring, to_string #include <string> // for string, wstring, to_string
#include <string_view> // for string_view
#include <vector> // for vector #include <vector> // for vector
namespace ftxui { namespace ftxui {
std::string to_string(std::wstring_view s); std::string to_string(const std::wstring& s);
std::wstring to_wstring(std::string_view s); std::wstring to_wstring(const std::string& s);
template <typename T> template <typename T>
std::wstring to_wstring(T s) { std::wstring to_wstring(T s) {
return to_wstring(std::string_view(std::to_string(s))); return to_wstring(std::to_string(s));
}
template <>
inline std::wstring to_wstring(const char* s) {
return to_wstring(std::string_view(s));
} }
int string_width(std::string_view); int string_width(const std::string&);
// Split the string into a its glyphs. An empty one is inserted ater fullwidth // Split the string into a its glyphs. An empty one is inserted ater fullwidth
// ones. // ones.
std::vector<std::string> Utf8ToGlyphs(std::string_view input); std::vector<std::string> Utf8ToGlyphs(const std::string& input);
// Map every cells drawn by |input| to their corresponding Glyphs. Half-size // Map every cells drawn by |input| to their corresponding Glyphs. Half-size
// Glyphs takes one cell, full-size Glyphs take two cells. // Glyphs takes one cell, full-size Glyphs take two cells.
std::vector<int> CellToGlyphIndex(std::string_view input); std::vector<int> CellToGlyphIndex(const std::string& input);
} // namespace ftxui } // namespace ftxui

View File

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

View File

@@ -7,7 +7,6 @@
#include <ftxui/screen/string.hpp> #include <ftxui/screen/string.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view>
#include <variant> #include <variant>
#include <vector> #include <vector>
@@ -18,13 +17,8 @@ template <typename T>
class ConstRef { class ConstRef {
public: public:
ConstRef() = default; ConstRef() = default;
// Owning constructors:
ConstRef(T t) : variant_(std::move(t)) {} // NOLINT ConstRef(T t) : variant_(std::move(t)) {} // NOLINT
// Referencing constructors:
ConstRef(const T* t) : variant_(t) {} // NOLINT ConstRef(const T* t) : variant_(t) {} // NOLINT
ConstRef& operator=(ConstRef&&) noexcept = default; ConstRef& operator=(ConstRef&&) noexcept = default;
ConstRef(const ConstRef<T>&) = default; ConstRef(const ConstRef<T>&) = default;
ConstRef(ConstRef<T>&&) noexcept = default; ConstRef(ConstRef<T>&&) noexcept = default;
@@ -52,13 +46,8 @@ template <typename T>
class Ref { class Ref {
public: public:
Ref() = default; Ref() = default;
// Owning constructors:
Ref(T t) : variant_(std::move(t)) {} // NOLINT Ref(T t) : variant_(std::move(t)) {} // NOLINT
//
// Referencing constructors:
Ref(T* t) : variant_(t) {} // NOLINT Ref(T* t) : variant_(t) {} // NOLINT
//
~Ref() = default; ~Ref() = default;
Ref& operator=(Ref&&) noexcept = default; Ref& operator=(Ref&&) noexcept = default;
Ref(const Ref<T>&) = default; Ref(const Ref<T>&) = default;
@@ -94,15 +83,10 @@ class StringRef : public Ref<std::string> {
public: public:
using Ref<std::string>::Ref; using Ref<std::string>::Ref;
// Owning constructors:
StringRef(const wchar_t* ref) // NOLINT StringRef(const wchar_t* ref) // NOLINT
: StringRef(to_string(std::wstring(ref))) {} : StringRef(to_string(std::wstring(ref))) {}
StringRef(const char* ref) // NOLINT StringRef(const char* ref) // NOLINT
: StringRef(std::string(ref)) {} : StringRef(std::string(ref)) {}
StringRef(std::string_view ref) // NOLINT
: StringRef(std::string(ref)) {}
StringRef(std::wstring_view ref) // NOLINT
: StringRef(to_string(ref)) {}
}; };
/// @brief An adapter. Own or reference a constant string. For convenience, this /// @brief An adapter. Own or reference a constant string. For convenience, this
@@ -111,21 +95,14 @@ class ConstStringRef : public ConstRef<std::string> {
public: public:
using ConstRef<std::string>::ConstRef; using ConstRef<std::string>::ConstRef;
// Referencing constructors:
ConstStringRef(const std::wstring* ref) // NOLINT ConstStringRef(const std::wstring* ref) // NOLINT
: ConstStringRef(to_string(*ref)) {} : ConstStringRef(to_string(*ref)) {}
// Owning constructors:
ConstStringRef(const std::wstring ref) // NOLINT ConstStringRef(const std::wstring ref) // NOLINT
: ConstStringRef(to_string(ref)) {} : ConstStringRef(to_string(ref)) {}
ConstStringRef(std::wstring_view ref) // NOLINT
: ConstStringRef(to_string(ref)) {}
ConstStringRef(const wchar_t* ref) // NOLINT ConstStringRef(const wchar_t* ref) // NOLINT
: ConstStringRef(to_string(std::wstring(ref))) {} : ConstStringRef(to_string(std::wstring(ref))) {}
ConstStringRef(const char* ref) // NOLINT ConstStringRef(const char* ref) // NOLINT
: ConstStringRef(std::string(ref)) {} : ConstStringRef(std::string(ref)) {}
ConstStringRef(std::string_view ref) // NOLINT
: ConstStringRef(std::string(ref)) {}
}; };
/// @brief An adapter. Reference a list of strings. /// @brief An adapter. Reference a list of strings.
@@ -148,12 +125,10 @@ class ConstStringListRef {
Adapter& operator=(Adapter&&) = default; Adapter& operator=(Adapter&&) = default;
virtual ~Adapter() = default; virtual ~Adapter() = default;
virtual size_t size() const = 0; virtual size_t size() const = 0;
virtual std::string_view operator[](size_t i) const = 0; virtual std::string operator[](size_t i) const = 0;
}; };
using Variant = std::variant<const std::vector<std::string>, // using Variant = std::variant<const std::vector<std::string>, //
const std::vector<std::string>*, // const std::vector<std::string>*, //
const std::vector<std::string_view>, //
const std::vector<std::string_view>*, //
const std::vector<std::wstring>*, // const std::vector<std::wstring>*, //
Adapter*, // Adapter*, //
std::unique_ptr<Adapter> // std::unique_ptr<Adapter> //
@@ -166,26 +141,25 @@ class ConstStringListRef {
ConstStringListRef(ConstStringListRef&&) = default; ConstStringListRef(ConstStringListRef&&) = default;
ConstStringListRef(const ConstStringListRef&) = default; ConstStringListRef(const ConstStringListRef&) = default;
ConstStringListRef(std::vector<std::string> value) { // NOLINT ConstStringListRef(std::vector<std::string> value) // NOLINT
{
variant_ = std::make_shared<Variant>(value); variant_ = std::make_shared<Variant>(value);
} }
ConstStringListRef(const std::vector<std::string>* value) {// NOLINT ConstStringListRef(const std::vector<std::string>* value) // NOLINT
{
variant_ = std::make_shared<Variant>(value); variant_ = std::make_shared<Variant>(value);
} }
ConstStringListRef(std::vector<std::string_view> value) { // NOLINT ConstStringListRef(const std::vector<std::wstring>* value) // NOLINT
{
variant_ = std::make_shared<Variant>(value); variant_ = std::make_shared<Variant>(value);
} }
ConstStringListRef(const std::vector<std::string_view>* value) { // NOLINT ConstStringListRef(Adapter* adapter) // NOLINT
variant_ = std::make_shared<Variant>(value); {
}
ConstStringListRef(const std::vector<std::wstring>* value) { // NOLINT
variant_ = std::make_shared<Variant>(value);
}
ConstStringListRef(Adapter* adapter) { // NOLINT
variant_ = std::make_shared<Variant>(adapter); variant_ = std::make_shared<Variant>(adapter);
} }
template <typename AdapterType> template <typename AdapterType>
ConstStringListRef(std::unique_ptr<AdapterType> adapter) { // NOLINT ConstStringListRef(std::unique_ptr<AdapterType> adapter) // NOLINT
{
variant_ = std::make_shared<Variant>( variant_ = std::make_shared<Variant>(
static_cast<std::unique_ptr<Adapter>>(std::move(adapter))); static_cast<std::unique_ptr<Adapter>>(std::move(adapter)));
} }
@@ -194,34 +168,11 @@ class ConstStringListRef {
return variant_ ? std::visit(SizeVisitor(), *variant_) : 0; return variant_ ? std::visit(SizeVisitor(), *variant_) : 0;
} }
std::string_view operator[](size_t i) const { std::string operator[](size_t i) const {
return variant_ ? std::visit(IndexedGetter{i}, *variant_) : ""; return variant_ ? std::visit(IndexedGetter(i), *variant_) : "";
} }
private: private:
struct IndexedGetter {
size_t i;
std::string_view operator()(const std::vector<std::string>& v) const {
return v[i];
}
std::string_view operator()(const std::vector<std::string>* v) const {
return (*v)[i];
}
std::string_view operator()(const std::vector<std::string_view>& v) const {
return std::string(v[i]);
}
std::string_view operator()(const std::vector<std::string_view>* v) const {
return std::string((*v)[i]);
}
std::string_view operator()(const std::vector<std::wstring>* v) const {
return to_string((*v)[i]);
}
std::string_view operator()(Adapter* v) const { return std::string((*v)[i]); }
std::string_view operator()(const std::unique_ptr<Adapter>& v) const {
return (*v)[i];
}
};
struct SizeVisitor { struct SizeVisitor {
size_t operator()(const std::vector<std::string>& v) const { size_t operator()(const std::vector<std::string>& v) const {
return v.size(); return v.size();
@@ -229,12 +180,6 @@ class ConstStringListRef {
size_t operator()(const std::vector<std::string>* v) const { size_t operator()(const std::vector<std::string>* v) const {
return v->size(); return v->size();
} }
size_t operator()(const std::vector<std::string_view>& v) const {
return v.size();
}
size_t operator()(const std::vector<std::string_view>* v) const {
return v->size();
}
size_t operator()(const std::vector<std::wstring>* v) const { size_t operator()(const std::vector<std::wstring>* v) const {
return v->size(); return v->size();
} }
@@ -244,6 +189,25 @@ class ConstStringListRef {
} }
}; };
struct IndexedGetter {
IndexedGetter(size_t index) // NOLINT
: index_(index) {}
size_t index_;
std::string operator()(const std::vector<std::string>& v) const {
return v[index_];
}
std::string operator()(const std::vector<std::string>* v) const {
return (*v)[index_];
}
std::string operator()(const std::vector<std::wstring>* v) const {
return to_string((*v)[index_]);
}
std::string operator()(const Adapter* v) const { return (*v)[index_]; }
std::string operator()(const std::unique_ptr<Adapter>& v) const {
return (*v)[index_];
}
};
std::shared_ptr<Variant> variant_; std::shared_ptr<Variant> variant_;
}; };

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 +1,18 @@
/// @module ftxui.component /**
/// @brief Module file for FTXUI component operations. * @file component.cppm
* @brief Module file for FTXUI component operations.
*/
export module ftxui.component; export module ftxui.component;
export import :Animation; export import ftxui.component.animation;
export import :CapturedMouse; export import ftxui.component.captured_mouse;
export import :Component; export import ftxui.component.component;
export import :ComponentBase; export import ftxui.component.component_base;
export import :ComponentOptions; export import ftxui.component.component_options;
export import :Event; export import ftxui.component.event;
export import :Loop; export import ftxui.component.loop;
export import :Mouse; export import ftxui.component.mouse;
export import :Receiver; export import ftxui.component.receiver;
export import :ScreenInteractive; export import ftxui.component.screen_interactive;
export import :Task; export import ftxui.component.task;

View File

@@ -1,12 +1,13 @@
/// @module ftxui.component:Animation /// @module ftxui.component.animation
/// @brief C++20 module interface for the Animation namespace of the Component module. /// @brief Module file for the Animation namespace of the Component module.
/// ///
/// @file animation.cppm
module; module;
#include <ftxui/component/animation.hpp> #include <ftxui/component/animation.hpp>
export module ftxui.component:Animation; export module ftxui.component.animation;
/** /**
* @namespace ftxui::animation * @namespace ftxui::animation
@@ -23,7 +24,7 @@ export namespace ftxui::animation {
/** /**
* @namespace easing * @namespace easing
* @brief The FTXUI ftxui::animation::easing:: namespace * @brief The FTXUI sf::animation::easing:: namespace
*/ */
namespace easing { namespace easing {
using ftxui::animation::easing::Function; using ftxui::animation::easing::Function;

View File

@@ -48,7 +48,7 @@ class ButtonBase : public ComponentBase, public ButtonOption {
} }
const EntryState state{ const EntryState state{
std::string(*label), false, active, focused_or_hover, Index(), *label, false, active, focused_or_hover, Index(),
}; };
auto element = (transform ? transform : DefaultTransform) // auto element = (transform ? transform : DefaultTransform) //
@@ -139,6 +139,7 @@ class ButtonBase : public ComponentBase, public ButtonOption {
private: private:
bool mouse_hover_ = false; bool mouse_hover_ = false;
Box box_; Box box_;
ButtonOption option_;
float animation_background_ = 0; float animation_background_ = 0;
float animation_foreground_ = 0; float animation_foreground_ = 0;
animation::Animator animator_background_ = animation::Animator animator_background_ =

View File

@@ -1,11 +1,13 @@
/// @module ftxui.component.CapturedMouse /**
/// @brief Module file for the CapturedMouseInterface class of the Component module * @file captured_mouse.cppm
* @brief Module file for the CapturedMouseInterface class of the Component module
*/
module; module;
#include <ftxui/component/captured_mouse.hpp> #include <ftxui/component/captured_mouse.hpp>
export module ftxui.component:CapturedMouse; export module ftxui.component.captured_mouse;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -27,7 +27,7 @@ class CheckboxBase : public ComponentBase, public CheckboxOption {
const bool is_focused = Focused(); const bool is_focused = Focused();
const bool is_active = Active(); const bool is_active = Active();
auto entry_state = EntryState{ auto entry_state = EntryState{
std::string(*label), *checked, is_active, is_focused || hovered_, -1, *label, *checked, is_active, is_focused || hovered_, -1,
}; };
auto element = (transform ? transform : CheckboxOption::Simple().transform)( auto element = (transform ? transform : CheckboxOption::Simple().transform)(
entry_state); entry_state);

View File

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

View File

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

View File

@@ -1,11 +1,13 @@
/// @module ftxui.component:Component /**
/// @brief Module file for the Component classes of the Component module * @file component.cppm
* @brief Module file for the Component classes of the Component module
*/
module; module;
#include <ftxui/component/component.hpp> #include <ftxui/component/component.hpp>
export module ftxui.component:Component; export module ftxui.component.component;
/** /**
* @namespace ftxui * @namespace ftxui
@@ -28,10 +30,6 @@ export namespace ftxui {
using ftxui::operator|; using ftxui::operator|;
using ftxui::operator|=; using ftxui::operator|=;
/**
* @namespace Container
* @brief The FTXUI ftxui::Container:: namespace
*/
namespace Container { namespace Container {
using ftxui::Container::Vertical; using ftxui::Container::Vertical;
using ftxui::Container::Horizontal; using ftxui::Container::Horizontal;

View File

@@ -1,11 +1,13 @@
/// @module ftxui.component:ComponentBase /**
/// @brief Module file for the ComponentBase class of the Component module * @file component_base.cppm
* @brief Module file for the ComponentBase class of the Component module
*/
module; module;
#include <ftxui/component/component_base.hpp> #include <ftxui/component/component_base.hpp>
export module ftxui.component:ComponentBase; export module ftxui.component.component_base;
/** /**
* @namespace ftxui * @namespace ftxui
@@ -16,10 +18,6 @@ export namespace ftxui {
using ftxui::Focus; using ftxui::Focus;
using ftxui::Event; using ftxui::Event;
/**
* @namespace animation
* @brief The FTXUI ftxui::animation:: namespace
*/
namespace animation { namespace animation {
using ftxui::animation::Params; using ftxui::animation::Params;
} }

View File

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

View File

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

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