79 Commits

Author SHA1 Message Date
Arthur Sonzogni
751c8fab26 Force reload in examples. (#974)
After installing the service worker to use the COOP/COEP header, ensure
the document is reloaded.

Bug:https://github.com/ArthurSonzogni/FTXUI/issues/973
Fixed:https://github.com/ArthurSonzogni/FTXUI/issues/973
2024-12-25 13:32:35 +01:00
Sumit Patel
daa421fa6a add tuisic example project (#967) 2024-12-15 18:58:08 +01:00
Yongqi Zhu
e213cfda37 add Lazylist example project (#964) 2024-12-06 15:20:17 +01:00
Vemy
58ff448e76 Fix: Properly changing window title text color #940 (#961) 2024-12-01 09:38:09 +01:00
Dmitry Nefedov
dfa461b46b Clear terminal output of interactive screen on resize if alternate screen not in use (#952) 2024-11-27 21:52:20 +01:00
Dmitry Atamanov
0683285f01 Remove non-existent Just-Fast from README.md (#957) 2024-11-27 21:47:09 +01:00
glebundiy
7f74917887 Add yafth as an example project using FTXUI (#958) 2024-11-27 21:44:32 +01:00
Brian
ad0392ec39 Fixed typo on border (#956)
Fixed minor issue in function name
2024-11-20 22:37:02 +01:00
Boris Jaulmes
70bc44d28b Allow a Dimension::Fit to extend beyond the terminal maximum height (#950)
For long tables (and other DOM elements), one may want the screen to render on dimensions higher than the terminal.  
Hence, this PR proposes a way to do so, with an optional parameter in the `Dimension::Fit` util function.

Discussions / Issues :  
- https://github.com/ArthurSonzogni/FTXUI/issues/572
- https://github.com/ArthurSonzogni/FTXUI/discussions/949

Bug:https://github.com/ArthurSonzogni/FTXUI/issues/572
Fixed:Bug:https://github.com/ArthurSonzogni/FTXUI/issues/572
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-11-07 21:07:09 +01:00
Petr Vyazovik
55af678fb9 Added pciex as an example project using FTXUI (#948) 2024-11-02 12:08:43 +01:00
Mikołaj Lubiak
edaa7a24e7 Add memory game and terminal animation to project list (#946) 2024-10-31 21:09:42 +01:00
Vemy
8922e6d55e Add 2048-cpp to projects using FTXUI (#944) 2024-10-29 09:15:07 +01:00
Mikołaj Lubiak
99df1ac8ba Add SliderWithCallback component (#938)
Add SliderOption::on_change.

Useful to observe a change to the value.

Signed-off-by: Mikołaj Lubiak <lubiak@proton.me>
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-10-29 08:03:59 +01:00
Herring
1d40687a40 Add index to EntryState (#933)
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-09-30 23:18:59 +02:00
ljrrjl
dfb9558eaf add ftxui-image-view (#924) 2024-08-27 14:35:15 +02:00
ArthurSonzogni
c5357acbaa Add scrollbar example. 2024-08-18 10:46:41 +02:00
ArthurSonzogni
fbd56cdf43 Fix CQ failures. 2024-08-17 12:01:43 +02:00
ArthurSonzogni
66d1c1f61f Quickfix 2024-08-16 11:47:01 +02:00
Arthur Sonzogni
f5d8c7deb5 Apply Clang-tidy (#918) 2024-08-16 11:19:51 +02:00
Sergey Latu
535290bb3b My project added to readme (#916) 2024-08-15 16:08:32 +02:00
Arthur Sonzogni
fcd050c017 Table: support initializer list constructor. (#915)
To avoid burdening the user with explicit type construction when using
the library, we can use a constructor that accepts an initializer list
(std::initializer_list). This allows users to pass initializer lists
directly without having to wrap them in
std::vector<std::vector<std::string>>. This resolves the ambiguous case
when the inner list contains only two elements.

Bug:https://github.com/ArthurSonzogni/FTXUI/issues/912
2024-08-13 15:55:09 +02:00
Paolo Bosetti
d7de24cd9e Added -fPIC compile option (#913)
Added -fPIC compile option.
2024-08-11 19:17:57 +02:00
Charney Kaye
547d9278d8 Add XJ music to FTXUI example projects (#909)
We use FTXUI as the frontend for the example C++ application for our adaptive music runtime engine.

https://github.com/xjmusic/xjmusic/tree/main/engine/example
2024-08-04 11:05:59 +02:00
Brian
5a9ef876a1 Update README.md (#905)
added step writer
2024-07-25 11:07:38 +02:00
LiAuTraver
307e4eb4b3 add missing include guard for screen/pixel.hpp (#890) 2024-06-27 13:07:10 +02:00
sAkuraOfficial
b28d57086a fix a small bug in button example (#868) 2024-06-13 18:43:49 +02:00
Arthur Sonzogni
ff305147ca Color alpha support. (#884) 2024-06-13 18:43:14 +02:00
Timon Ensel
d6a2049483 Add ostree-tui to README (#874) 2024-06-09 15:50:01 +02:00
Dr Power
b5e11ba1f6 Added Caravan to README.md (#871) 2024-06-09 15:44:12 +02:00
ArthurSonzogni
a715a767b5 Fix Color::HSV(h,0,v)
There was a problem when v==0
2024-06-02 12:03:41 +02:00
Felix
7b1f4d435b Solve issues with atomic copy (#867) 2024-05-26 15:28:05 +02:00
Arthur Sonzogni
ecacb22d37 Dropdown: Fix title not updated. (#851)
A bug was introduced by:
https://github.com/ArthurSonzogni/FTXUI/pull/826

The checkbox label wasn't updated.

Bug:https://github.com/ArthurSonzogni/FTXUI/issues/861
2024-05-15 18:23:59 +02:00
ArthurSonzogni
af49b57e60 Dropdown: Fix title not updated.
A bug was introduced by:
https://github.com/ArthurSonzogni/FTXUI/pull/826

The checkbox label wasn't updated.

Bug:https://github.com/ArthurSonzogni/FTXUI/issues/861
2024-05-13 10:53:11 +02:00
ccn
4913379625 Update index.html (#858)
correct spelling
2024-05-06 12:54:17 +02:00
ccn
d40cafde5c Update homescreen.cpp (#859)
fix typo
2024-05-06 12:53:56 +02:00
ccn
65296b9aa3 Update flex.cpp (#860)
fix typo
2024-05-06 12:53:37 +02:00
ccn
a58e6e6bcf Update README.md (#857)
minor typo
2024-05-05 18:11:07 +02:00
Arthur Sonzogni
8a2a9b0799 Generate compile commands for clangd. (#855)
Fix all the diagnostics reported.

Bug: https://github.com/ArthurSonzogni/FTXUI/issues/828
2024-05-01 14:32:22 +02:00
Arthur Sonzogni
6a755f3760 Fix Menu focus. (#850)
Bug:https://github.com/ArthurSonzogni/FTXUI/issues/841
2024-04-28 16:03:00 +02:00
Jørn Gustav Larsen
d386df6f94 Enable raw keyboard input (#832)
In order for applications to receive all keyboard inputs, including the
Ctrl-C and Ctrl-Z, the raw input mode has been enabled. As result the
SIGINT will no longer be used, instead the keyboard Ctrl-C event is used
for exiting the framework, but only if no components has made use of it.

Co-authored-by: Jørn Gustav Larsen <jgl@fasttracksoftware.com>
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-04-28 15:17:54 +02:00
Mark Antabi
d38b14ffb6 Allow user to specify window element border. (#849) 2024-04-28 14:48:02 +02:00
ArthurSonzogni
7e3e1d4bca Apply clang-tidy. 2024-04-28 10:40:57 +02:00
Clancy Walters
affa787244 Prefer Exit() over OnExit() (#847)
This is a no-op patch, but prefered, because this centralize the exit path below `Exit()`.
2024-04-27 11:32:46 +02:00
Arthur Sonzogni
014bdb4a05 Flush before applying a new configuration. (#848)
This avoids an ordering problem with whatever the user printed and
interacting with termios/WinAPI.

Bug:https://github.com/ArthurSonzogni/FTXUI/issues/846
2024-04-27 11:18:35 +02:00
Dimo Markov
293ff179f6 Separate a reusable Image class from Screen (#834)
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-04-27 11:03:44 +02:00
cole-io
1f6e1101e8 clarified README and added tip on linking (#845)
Clarified some sentences, changed "external package" section to "utilization", added a tip on linking
2024-04-22 08:48:32 +02:00
na-trium-144
0dfd59bd09 Fix ResizableSplit handling keyboard navigation incorrectly (#842)
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-04-18 17:28:28 +02:00
ArthurSonzogni
e03a0797be Fix minor compile error. 2024-04-07 18:10:52 +02:00
James
3c9fa60d28 Feature: Dropdown options with callback (#826)
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-04-06 17:45:10 +02:00
Jørn Gustav Larsen
2216f3a5da Problem with setting the cursor position on the right screen edge when drawing. (#831)
When moving the cursor back to its original location, a problem arises when cursor placed in the right edge column, where an off by one error occur. This pull request will resolve this problem.

Co-authored-by: Jørn Gustav Larsen <jgl@fasttracksoftware.com>
Co-authored-by: Jørn Gustav Larsen <jgl@adminbyrequest.com>
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2024-04-03 21:32:19 +02:00
Arthur Sonzogni
f609c12846 Revert change to button example. (#835)
It was introduced mistakenly by:
f495ce029c
2024-03-30 11:01:28 +01:00
faizan171997
ce5ac6b12f - Added exit button to homescreen example (#819) 2024-02-22 12:12:51 +01:00
ArthurSonzogni
f495ce029c Add example to use system ftxui
Fixed: https://github.com/ArthurSonzogni/FTXUI/issues/814
2024-01-26 18:32:44 +01:00
Arthur Sonzogni
810657dab8 Update mainpage.md
Fixed: https://github.com/ArthurSonzogni/FTXUI/issues/812
2024-01-25 11:56:25 +01:00
rio
65bbb4f0eb Make Checkbox take focus when clicked (#810) 2024-01-17 18:21:32 +01:00
Arthur Sonzogni
5112d9139d Button: invoke on_click at the end. (#807)
Some users might destroy `this`, which would result in UAF.

In the future, we should consider alternatives like posting a task to
the main loop, or rely on users for this.

Fixed:https://github.com/ArthurSonzogni/FTXUI/issues/804
2024-01-10 22:08:57 +01:00
Mohammad Rahimi
91a162a30e Add FTowerX to README (#805)
FTowerX is Tower of Hanoi game developed using FTXUI
2024-01-08 16:48:42 +01:00
Nikola Dućak
4d5cc41c65 Add Captain's log to README (#803) 2024-01-08 07:25:38 +01:00
nyako
cc3bcbf069 ftxui_set_options: properly check the current compiler. (#802)
This solve the issue encountered when using clang under MSVC.
2024-01-08 07:05:41 +01:00
Particle_G
d0634e1ca0 Add missing Checkbox() implementation (#796)
Fix: #795
2023-12-23 08:35:20 +01:00
Arthur Sonzogni
a7b6785420 Restore cursor shape on exit. (#793) (#794)
Fixed: https://github.com/ArthurSonzogni/FTXUI/issues/792
2023-12-17 10:35:21 +01:00
Arthur Sonzogni
348c3853d4 Restore cursor shape on exit. (#793)
Fixed: https://github.com/ArthurSonzogni/FTXUI/issues/792
2023-12-17 10:24:33 +01:00
ArthurSonzogni
bfadcb7165 Fix default for ScreenInteractive::Fullscreen()
It was intended to open gthe alternate screen.
2023-11-19 14:09:42 +01:00
Arthur Sonzogni
6c2b43a2aa Improve the example page. (#780) 2023-11-19 12:09:52 +01:00
Arthur Sonzogni
b970cb6ea8 feature: allow fullscreen without alternative screen (#777)
This should solve #766

The original PR was:
#767

Co-authored-by: rbrugo <brugo.riccardo@gmail.com>
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2023-11-11 17:57:07 +01:00
Clément Roblot
c31aecf2ed Checkbox button debounce (#774)
This fixes: https://github.com/ArthurSonzogni/FTXUI/issues/773

Dragging the mouse with the left button pressed now avoids activating multiple
checkboxes.

Add support for detecting mouse press transition. Added:
```cpp
// The previous mouse event.
Mouse Mouse::previous;

// Return whether the mouse transitionned from:
// released to pressed => IsPressed()
// pressed to pressed => IsHeld()
// pressed to released => IsReleased()
bool Mouse::IsPressed(Button button) const;
bool Mouse::IsHeld(Button button) const;
bool Mouse::IsReleased(Button button) const;
```
A couple of components are now activated when the mouse is pressed,
as opposed to released.

Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2023-11-11 17:33:50 +01:00
chrysante
e8589dd533 Fix Input onchange not called (#776) 2023-11-11 17:29:19 +01:00
Clément Roblot
0631c3ab3f Add example to filter characters inputted in an input field (#763)
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2023-11-05 10:26:12 +01:00
Ali Caglayan
d548a18658 update nix and add dev shell (#769)
We update the lock on the nix flake and also add a dev shell. This means
you can do `nix build` to build the project and `nix develop` to drop
into a development environment with cmake and clang.

Signed-off-by: Ali Caglayan <alizter@gmail.com>
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
2023-10-23 08:48:50 +02:00
benoitdudu
f499d34f7e fix the doxygen documentation by moving comments at the right place (#768) 2023-10-19 16:58:02 -04:00
Ruebled
d4c9c5e226 Update README.md (#761)
Version FetchContent Update
2023-10-12 17:27:18 +02:00
Clément Roblot
62c0b43caf Scrollbar coloring (#755)
This a proposed MR to fix #754. While building the scroll bar the pixels were completely reseted thus canceling any style previously applied to said pixels. This MR removes this resetting of the pixels and leaves only the drawing of the shape of the scroll bar.
2023-10-02 10:29:23 +02:00
Arthur Sonzogni
c24a274292 Feature: hscroll_indicator (#753)
This is the symetrical of `vscroll_indicator`.

Requested by @ibrahimnasson.

Fixed:https://github.com/ArthurSonzogni/FTXUI/issues/752
2023-09-26 23:08:42 +02:00
Contexploit
20d4be286b Example: fix small flaw in example/button.cpp (#751) 2023-09-20 18:23:05 +02:00
Arthur Sonzogni
550a59f0a5 Add catalincd/resource-monitor (#745) 2023-09-18 20:10:48 +02:00
Arthur Sonzogni
5db2be0f4d List J0sephDavis/ftxuiFileReader (#746) 2023-09-18 20:09:45 +02:00
Arthur Sonzogni
8d1665022a List ftxui_CPUMeter (#744) 2023-09-03 16:21:13 +02:00
Arthur Sonzogni
e5978a8e76 Update README.md 2023-09-03 11:45:23 +02:00
MingSheng
0f1588e3d1 Add grid container library (#742) 2023-09-02 11:00:45 +02:00
27 changed files with 587 additions and 251 deletions

View File

@@ -220,6 +220,8 @@ jobs:
rsync -amv
--include='*/'
--include='*.html'
--include='*.css'
--include='*.mjs'
--include='*.js'
--include='*.wasm'
--exclude='*'

10
.gitignore vendored
View File

@@ -38,14 +38,16 @@ out/
!doc/**/*.md
# examples directory:
!examples/**/*.txt
!examples/**/*.cpp
!examples/**/*.css
!examples/**/*.hpp
!examples/**/*.ipp
!examples/**/*.html
!examples/**/*.py
!examples/**/*.js
!examples/**/*.html.disabled
!examples/**/*.ipp
!examples/**/*.js
!examples/**/*.mjs
!examples/**/*.py
!examples/**/*.txt
# include directory:
!include/ftxui/**/*.hpp

View File

@@ -35,6 +35,10 @@ current (development)
- Bugfix: Fix cursor position in when in the last column. See #831.
- Bugfix: Fix `ResizeableSplit` keyboard navigation. Fixed by #842.
- Bugfix: Fix `Menu` focus. See #841
- Feature: Add `ComponentBase::Index()`. This allows to get the index of a
component in its parent. See #932
- Feature: Add `EntryState::index`. This allows to get the index of a menu entry.
See #932
- Feature: Add `SliderOption::on_change`. This allows to set a callback when the
slider value changes. See #938.

View File

@@ -43,7 +43,7 @@ A simple cross-platform C++ library for terminal based user interfaces!
* **Cross platform**: Linux/MacOS (main target), WebAssembly, Windows (Thanks to contributors!).
* Learn by [examples](#documentation), and [tutorials](#documentation)
* Multiple packages: CMake [FetchContent]([https://bewagner.net/programming/2020/05/02/cmake-fetchcontent/](https://cmake.org/cmake/help/latest/module/FetchContent.html)) (preferred), vcpkg, pkgbuild, conan.
* Good practises: documentation, tests, fuzzers, performance tests, automated CI, automated packaging, etc...
* Good practices: documentation, tests, fuzzers, performance tests, automated CI, automated packaging, etc...
## Documentation
@@ -73,7 +73,7 @@ A simple cross-platform C++ library for terminal based user interfaces!
#### DOM
This module defines a hierarchical set of Element. An element manages layout and can be responsive to the terminal dimensions.
This module defines a hierarchical set of Element. An Element manages layout and can be responsive to the terminal dimensions.
They are declared in [<ftxui/dom/elements.hpp>](https://arthursonzogni.github.io/FTXUI/elements_8hpp_source.html
)
@@ -199,7 +199,7 @@ Complex [examples](https://github.com/ArthurSonzogni/FTXUI/blob/master/examples/
#### Component
The ftxui/component is needed when you want to produce dynamic UI, reactive to the user's input. It defines a set of ftxui::Component. A component reacts to Events (keyboard, mouse, resize, ...) and Render Element (see previous section).
ftxui/component produces dynamic UI, reactive to the user's input. It defines a set of ftxui::Component. A component reacts to Events (keyboard, mouse, resize, ...) and Renders as an Element (see previous section).
Prebuilt components are declared in [<ftxui/component/component.hpp>](https://arthursonzogni.github.io/FTXUI/component_8hpp_source.html)
@@ -293,7 +293,10 @@ Prebuilt components are declared in [<ftxui/component/component.hpp>](https://ar
</details>
## Libraries for FTXUI
- *Want to share a useful component using FTXUI? Feel free adding yours here*
- *Want to share a useful Component for FTXUI? Feel free to add yours here*
- [ftxui-grid-container](https://github.com/mingsheng13/grid-container-ftxui)
- [ftxui-ip-input](https://github.com/mingsheng13/ip-input-ftxui)
- [ftxui-image-view](https://github.com/ljrrjl/ftxui-image-view.git): For Image Display.
## Project using FTXUI
@@ -301,12 +304,12 @@ Prebuilt components are declared in [<ftxui/component/component.hpp>](https://ar
Feel free to add your projects here:
- [json-tui](https://github.com/ArthurSonzogni/json-tui)
- [git-tui](https://github.com/ArthurSonzogni/git-tui)
- [ostree-tui](https://github.com/AP-Sensing/ostree-tui)
- [rgb-tui](https://github.com/ArthurSonzogni/rgb-tui)
- [chrome-log-beautifier](https://github.com/ArthurSonzogni/chrome-log-beautifier)
- [x86-64 CPU Architecture Simulation](https://github.com/AnisBdz/CPU)
- [ltuiny](https://github.com/adrianoviana87/ltuiny)
- [i3-termdialogs](https://github.com/mibli/i3-termdialogs)
- [Just-Fast](https://github.com/GiuseppeCesarano/just-fast)
- [simpPRU](https://github.com/VedantParanjape/simpPRU)
- [Pigeon ROS TUI](https://github.com/PigeonSensei/Pigeon_ros_tui)
- [hastur](https://github.com/robinlinden/hastur)
@@ -323,6 +326,22 @@ Feel free to add your projects here:
- [eCAL monitor](https://github.com/eclipse-ecal/ecal)
- [Path Finder](https://github.com/Ruebled/Path_Finder)
- [rw-tui](https://github.com/LeeKyuHyuk/rw-tui)
- [resource-monitor](https://github.com/catalincd/resource-monitor)
- [ftxuiFileReader](https://github.com/J0sephDavis/ftxuiFileReader)
- [ftxui_CPUMeter](https://github.com/tzzzzzzzx/ftxui_CPUMeter)
- [Captain's log](https://github.com/nikoladucak/caps-log)
- [FTowerX](https://github.com/MhmRhm/FTowerX)
- [Caravan](https://github.com/r3w0p/caravan)
- [Step-Writer](https://github.com/BrianAnakPintar/step-writer)
- [XJ music](https://github.com/xjmusic/xjmusic)
- [UDP chat](https://github.com/Sergeydigl3/udp-chat-tui)
- [2048-cpp](https://github.com/Chessom/2048-cpp)
- [Memory game](https://github.com/mikolajlubiak/memory)
- [Terminal Animation](https://github.com/mikolajlubiak/terminal_animation)
- [pciex](https://github.com/s0nx/pciex)
- [Fallout terminal hacking](https://github.com/gshigin/yet-another-fallout-terminal-hacking-game)
- [Lazylist](https://github.com/zhuyongqi9/lazylist)
- [TUISIC](https://github.com/Dark-Kernel/tuisic)
### [cpp-best-practices/game_jam](https://github.com/cpp-best-practices/game_jam)
@@ -339,16 +358,15 @@ 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)
- [Consu](https://github.com/cpp-best-practices/game_jam/blob/main/Jam1_April_2022/consu.md)
## External package
## Utilization
It is **highly** recommended to use CMake FetchContent to depend on FTXUI. This
way you can 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.
```cmake
include(FetchContent)
FetchContent_Declare(ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
GIT_TAG v3.0.0
GIT_TAG v5.0.0
)
FetchContent_GetProperties(ftxui)
@@ -358,14 +376,21 @@ if(NOT ftxui_POPULATED)
endif()
```
If you don't, the following packages have been created:
If you don't, FTXUI may be used from the following packages:
- [vcpkg](https://vcpkgx.com/details.html?package=ftxui)
- [Arch Linux PKGBUILD](https://aur.archlinux.org/packages/ftxui-git/).
- [conan.io](https://conan.io/center/ftxui)
- [openSUSE](https://build.opensuse.org/package/show/devel:libraries:c_c++/ftxui)
-
[![Packaging status](https://repology.org/badge/vertical-allrepos/ftxui.svg)](https://repology.org/project/ftxui/versions)
If you choose to build and link FTXUI yourself, `ftxui-component` must be first in the linking order relative to the other FTXUI libraries, i.e.
```bash
g++ . . . -lftxui-component -lftxui-dom -lftxui-screen . . .
```
## Contributors
<a href="https://github.com/ArthurSonzogni/FTXUI/graphs/contributors">

View File

@@ -50,42 +50,17 @@ int main(void) {
└────┘└────────────────────────────────────┘└─────┘
```
# Build {#build}
## Configure {#configure}
### Using CMake and find_package {#build-cmake-find-package}
## Using CMake {#build-cmake}
Assuming FTXUI is available or installed on the system.
This is an example configuration for your **CMakeLists.txt**
CMakeLists.txt
**CMakeLists.txt**
```cmake
cmake_minimum_required (VERSION 3.11)
# --- Fetch FTXUI --------------------------------------------------------------
include(FetchContent)
set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE)
FetchContent_Declare(ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
# Important: Specify a GIT_TAG XXXXX here.
GIT_TAG main
)
FetchContent_GetProperties(ftxui)
if(NOT ftxui_POPULATED)
FetchContent_Populate(ftxui)
add_subdirectory(${ftxui_SOURCE_DIR} ${ftxui_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
# ------------------------------------------------------------------------------
project(ftxui-starter
LANGUAGES CXX
VERSION 1.0.0
)
find_package(ftxui 5 REQUIRED)
project(ftxui-starter LANGUAGES CXX VERSION 1.0.0)
add_executable(ftxui-starter src/main.cpp)
target_include_directories(ftxui-starter PRIVATE src)
target_link_libraries(ftxui-starter
PRIVATE ftxui::screen
PRIVATE ftxui::dom
@@ -94,7 +69,33 @@ target_link_libraries(ftxui-starter
```
Subsequently, you build the project in the standard fashion as follows:
### Using CMake and FetchContent {#build-cmake}
If you want to fetch FTXUI using cmake:
**CMakeLists.txt**
```cmake
cmake_minimum_required (VERSION 3.11)
include(FetchContent)
set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE)
FetchContent_Declare(ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
GIT_TAG main # Important: Specify a version or a commit hash here.
)
FetchContent_MakeAvailable(ftxui)
project(ftxui-starter LANGUAGES CXX VERSION 1.0.0)
add_executable(ftxui-starter src/main.cpp)
target_link_libraries(ftxui-starter
PRIVATE ftxui::screen
PRIVATE ftxui::dom
PRIVATE ftxui::component # Not needed for this example.
)
```
## Build
```bash
mkdir build && cd build
cmake ..
@@ -634,6 +635,26 @@ Produced by: `ftxui::Input()` from "ftxui/component/component.hpp"
<script id="asciicast-223719" src="https://asciinema.org/a/223719.js" async></script>
@endhtmlonly
### Filtered input
On can filter out the characters received by the input component, using
`ftxui::CatchEvent`.
```cpp
std::string phone_number;
Component input = Input(&phone_number, "phone number");
// Filter out non-digit characters.
input |= CatchEvent([&](Event event) {
return event.is_character() && !std::isdigit(event.character()[0]);
});
// Filter out characters past the 10th one.
input |= CatchEvent([&](Event event) {
return event.is_character() && phone_number.size() >= 10;
});
```
## Menu {#component-menu}
Defines a menu object. It contains a list of entries, one of them is selected.

View File

@@ -21,6 +21,8 @@ if (EMSCRIPTEN)
get_property(EXAMPLES GLOBAL PROPERTY FTXUI::EXAMPLES)
foreach(file
"index.html"
"index.mjs"
"index.css"
"sw.js"
"run_webassembly.py")
configure_file(${file} ${file})

View File

@@ -38,6 +38,7 @@ example(radiobox)
example(radiobox_in_frame)
example(renderer)
example(resizable_split)
example(scrollbar)
example(slider)
example(slider_direction)
example(slider_rgb)

View File

@@ -34,8 +34,8 @@ 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_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
@@ -53,11 +53,9 @@ int main() {
return vbox({
text("value = " + std::to_string(value)),
separator(),
gauge(value * 0.01f),
separator(),
buttons->Render(),
buttons->Render() | flex,
}) |
border;
flex | border;
});
auto screen = ScreenInteractive::FitComponent();

View File

@@ -504,7 +504,10 @@ int main() {
auto main_renderer = Renderer(main_container, [&] {
return vbox({
text("FTXUI Demo") | bold | hcenter,
tab_selection->Render(),
hbox({
tab_selection->Render() | flex,
exit_button->Render(),
}),
tab_content->Render() | flex,
});
});

View File

@@ -15,30 +15,50 @@
int main() {
using namespace ftxui;
// The data:
std::string first_name;
std::string last_name;
std::string password;
std::string phoneNumber;
// The basic input components:
Component input_first_name = Input(&first_name, "first name");
Component input_last_name = Input(&last_name, "last name");
// The password input component:
InputOption password_option;
password_option.password = true;
Component input_password = Input(&password, "password", password_option);
// The phone number input component:
// We are using `CatchEvent` to filter out non-digit characters.
Component input_phone_number = Input(&phoneNumber, "phone number");
input_phone_number |= CatchEvent([&](Event event) {
return event.is_character() && !std::isdigit(event.character()[0]);
});
input_phone_number |= CatchEvent([&](Event event) {
return event.is_character() && phoneNumber.size() > 10;
});
// The component tree:
auto component = Container::Vertical({
input_first_name,
input_last_name,
input_password,
input_phone_number,
});
// Tweak how the component tree is rendered:
auto renderer = Renderer(component, [&] {
return vbox({
text("Hello " + first_name + " " + last_name),
separator(),
hbox(text(" First name : "), input_first_name->Render()),
hbox(text(" Last name : "), input_last_name->Render()),
hbox(text(" Password : "), input_password->Render()),
hbox(text(" Phone num : "), input_phone_number->Render()),
separator(),
text("Hello " + first_name + " " + last_name),
text("Your password is " + password),
text("Your phone number is " + phoneNumber),
}) |
border;
});

View File

@@ -0,0 +1,112 @@
// Copyright 2023 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/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
using namespace ftxui;
Component DummyWindowContent() {
class Impl : public ComponentBase {
private:
float scroll_x = 0.1;
float scroll_y = 0.1;
public:
Impl() {
auto content = Renderer([=] {
const std::string lorem =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed "
"do eiusmod tempor incididunt ut labore et dolore magna "
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
"ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis "
"aute irure dolor in reprehenderit in voluptate velit esse "
"cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia "
"deserunt mollit anim id est laborum.";
return vbox({
text(lorem.substr(0, -1)), text(lorem.substr(5, -1)), text(""),
text(lorem.substr(10, -1)), text(lorem.substr(15, -1)), text(""),
text(lorem.substr(20, -1)), text(lorem.substr(25, -1)), text(""),
text(lorem.substr(30, -1)), text(lorem.substr(35, -1)), text(""),
text(lorem.substr(40, -1)), text(lorem.substr(45, -1)), text(""),
text(lorem.substr(50, -1)), text(lorem.substr(55, -1)), text(""),
text(lorem.substr(60, -1)), text(lorem.substr(65, -1)), text(""),
text(lorem.substr(70, -1)), text(lorem.substr(75, -1)), text(""),
text(lorem.substr(80, -1)), text(lorem.substr(85, -1)), text(""),
text(lorem.substr(90, -1)), text(lorem.substr(95, -1)), text(""),
text(lorem.substr(100, -1)), text(lorem.substr(105, -1)), text(""),
text(lorem.substr(110, -1)), text(lorem.substr(115, -1)), text(""),
text(lorem.substr(120, -1)), text(lorem.substr(125, -1)), text(""),
text(lorem.substr(130, -1)), text(lorem.substr(135, -1)), text(""),
text(lorem.substr(140, -1)),
});
});
auto scrollable_content = Renderer(content, [&, content] {
return content->Render() | focusPositionRelative(scroll_x, scroll_y) |
frame | flex;
});
SliderOption<float> option_x;
option_x.value = &scroll_x;
option_x.min = 0.f;
option_x.max = 1.f;
option_x.increment = 0.1f;
option_x.direction = Direction::Right;
option_x.color_active = Color::Blue;
option_x.color_inactive = Color::BlueLight;
auto scrollbar_x = Slider(option_x);
SliderOption<float> option_y;
option_y.value = &scroll_y;
option_y.min = 0.f;
option_y.max = 1.f;
option_y.increment = 0.1f;
option_y.direction = Direction::Down;
option_y.color_active = Color::Yellow;
option_y.color_inactive = Color::YellowLight;
auto scrollbar_y = Slider(option_y);
Add(Container::Vertical({
Container::Horizontal({
scrollable_content,
scrollbar_y,
}) | flex,
Container::Horizontal({
scrollbar_x,
Renderer([] { return text(L"x"); }),
}),
}));
}
};
return Make<Impl>();
}
int main() {
auto window_1 = Window({
.inner = DummyWindowContent(),
.title = "First window",
.width = 80,
.height = 30,
});
auto window_2 = Window({
.inner = DummyWindowContent(),
.title = "My window",
.left = 40,
.top = 20,
.width = 80,
.height = 30,
});
auto window_container = Container::Stacked({
window_1,
window_2,
});
auto screen = ScreenInteractive::Fullscreen();
screen.Loop(window_container);
return EXIT_SUCCESS;
}

107
examples/index.css Normal file
View File

@@ -0,0 +1,107 @@
@import url(https://fonts.googleapis.com/css?family=Khula:700);
body {
background-color:#EEE;
padding:0px;
margin:0px;
font-family: Khula, Helvetica, sans-serif;
font-size: 130%;
}
.page {
max-width:1300px;
margin: auto;
padding: 10px;
}
a {
box-shadow: inset 0 0 0 0 #54b3d6;
color: #0087b9;
margin: 0 -.25rem;
padding: 0 .25rem;
transition: color .3s ease-in-out,
box-shadow .3s ease-in-out;
}
a:hover {
box-shadow: inset 120px 0 0 0 #54b3d6;
color: white;
}
h1 {
text-decoration: underline;
width:100%;
background-color: rgba(100,100,255,0.5);
padding: 10px;
margin: 0;
}
#selectExample {
flex:1;
}
#selectExample, #selectExample option {
font-size: 16px;
font-family: sans-serif;
font-weight: 700;
line-height: 1.3;
border:0px;
background-color: #bbb;
color:black;
}
#selectExample:focus {
outline:none;
}
#terminal {
width:100%;
height 500px;
height: calc(clamp(200px, 100vh - 300px, 900px));
overflow: hidden;
border:none;
background-color:black;
}
#terminalContainer {
overflow: hidden;
border-radius: 10px;
box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.75),
0px 2px 80px 0px rgba(0,0,0,0.50);
}
.fakeButtons {
height: 10px;
width: 10px;
border-radius: 50%;
border: 1px solid #000;
margin:6px;
background-color: #ff3b47;
border-color: #9d252b;
display: inline-block;
}
.fakeMinimize {
left: 11px;
background-color: #ffc100;
border-color: #9d802c;
}
.fakeZoom {
left: 16px;
background-color: #00d742;
border-color: #049931;
}
.fakeMenu {
display:flex;
flex-direction: row;
width:100%;
box-sizing: border-box;
height: 25px;
background-color: #bbb;
color:black;
margin: 0 auto;
overflow: hidden;
}

View File

@@ -1,174 +1,32 @@
<!DOCTYPE html> <html lang="en">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>FTXUI examples WebAssembly</title>
<script src="https://cdn.jsdelivr.net/npm/xterm@4.18.0/lib/xterm.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-webgl@0.11.4/lib/xterm-addon-webgl.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.min.js"></script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>➡️</text></svg>">
<link rel="stylesheet" href="index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@4.11.0/css/xterm.css"></link>
<!--Add COOP/COEP via a ServiceWorker to use SharedArrayBuffer-->
<script>
if ("serviceWorker" in navigator && !window.crossOriginIsolated) {
navigator.serviceWorker.register(new URL("./sw.js", location.href)).then(
registration => {
if (registration.active && !navigator.serviceWorker.controller) {
window.location.reload();
}
},
);
}
</script>
<script type="module" src="index.mjs"></script>
</head>
<body>
<script id="example_script"></script>
<div class="page">
<h1>FTXUI WebAssembly Example </h1>
<p>
<a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a simple
functional C++ library for terminal user interface. <br/>
This showcases the: <a href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a> folder. <br/>
</p>
<p>
On this page, you can try all the examples contained in: <a
href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a>
Those are compiled using WebAssembly.
</p>
<select id="selectExample"></select>
<div id="terminal"></div>
<div id="terminalContainer">
<div class="fakeMenu">
<div class="fakeButtons fakeClose"></div>
<div class="fakeButtons fakeMinimize"></div>
<div class="fakeButtons fakeZoom"></div>
<select id="selectExample"></select>
</div>
<div id="terminal"></div>
</div>
</div>
</body>
<script>
const example_list = "@EXAMPLES@".split(";");
const url_search_params = new URLSearchParams(window.location.search);
const example = url_search_params.get("file") || "dom/color_gallery";
const select = document.getElementById("selectExample");
for(var i = 0; i < example_list.length; i++) {
var opt = example_list[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
select.appendChild(el);
}
select.selectedIndex = example_list.findIndex(path => path == example) || 0;
select.addEventListener("change", () => {
location.href = (location.href).split('?')[0] + "?file=" +
example_list[select.selectedIndex];
});
let stdin_buffer = [];
const stdin = () => {
return stdin_buffer.shift() || 0;
}
let stdout_buffer = [];
const stdout = code => {
if (code == 0) {
term.write(new Uint8Array(stdout_buffer));
stdout_buffer = [];
} else {
stdout_buffer.push(code)
}
}
let stderrbuffer = [];
const stderr = code => {
if (code == 0 || code == 10) {
console.error(String.fromCodePoint(...stderrbuffer));
stderrbuffer = [];
} else {
stderrbuffer.push(code)
}
}
const term = new Terminal();
const term_element = document.querySelector('#terminal');
term.open(term_element);
const webgl_addon = new (WebglAddon.WebglAddon)();
term.loadAddon(webgl_addon);
const onBinary = e => {
for(c of e)
stdin_buffer.push(c.charCodeAt(0));
}
term.onBinary(onBinary);
term.onData(onBinary)
term.resize(140,43);
window.Module = {
preRun: () => {
FS.init(stdin, stdout, stderr);
},
postRun: [],
onRuntimeInitialized: () => {
if (window.Module._ftxui_on_resize == undefined)
return;
const fit_addon = new (FitAddon.FitAddon)();
term.loadAddon(fit_addon);
fit_addon.fit();
const resize_handler = () => {
const {cols, rows} = fit_addon.proposeDimensions();
term.resize(cols, rows);
window.Module._ftxui_on_resize(cols, rows);
};
const resize_observer = new ResizeObserver(resize_handler);
resize_observer.observe(term_element);
resize_handler();
// Disable scrollbar
term.write('\x1b[?47h')
},
};
const words = example.split('/')
words[1] = "ftxui_example_" + words[1] + ".js"
document.querySelector("#example_script").src = words.join('/');
</script>
<style>
body {
background-color:#EEE;
padding:20px;
font-family: Helvetica, sans-serif;
font-size: 130%;
}
.page {
max-width:1300px;
margin: auto;
}
h1 {
text-decoration: underline;
}
select {
display:block;
padding: .6em 1.4em .5em .8em;
border-radius: 20px 20px 0px 0px;
font-size: 16px;
font-family: sans-serif;
font-weight: 700;
color: #444;
line-height: 1.3;
background-color:black;
border:0px;
color:white;
transition: color 0.2s linear;
transition: background-color 0.2s linear;
}
#terminal {
width:100%;
height: 500px;
height: calc(clamp(200px, 100vh - 300px, 900px));
overflow: hidden;
border:none;
padding:auto;
}
</style>
</html>

100
examples/index.mjs Normal file
View File

@@ -0,0 +1,100 @@
import xterm from 'https://cdn.jsdelivr.net/npm/xterm@4.18.0/+esm'
import xterm_addon_webgl from 'https://cdn.jsdelivr.net/npm/xterm-addon-webgl@0.11.4/+esm'
import xterm_addon_fit from 'https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/+esm'
// Add COOP/COEP via a ServiceWorker to use SharedArrayBuffer
if ("serviceWorker" in navigator && !window.crossOriginIsolated) {
const url_sw = new URL("./sw.js", location.href);
const registration = await navigator.serviceWorker.register(url_sw);
window.location.reload(); // Reload to ensure the COOP/COEP headers are set.
}
const example_list = "@EXAMPLES@".split(";");
const url_search_params = new URLSearchParams(window.location.search);
const select = document.getElementById("selectExample");
for(const example of example_list) {
const option = document.createElement("option");
option.textContent = example;
option.value = example;
select.appendChild(option);
}
const example = url_search_params.get("file") || "dom/color_gallery";
select.selectedIndex = example_list.findIndex(path => path == example) || 0;
select.addEventListener("change", () => {
history.pushState({}, "", "?file=" + example_list[select.selectedIndex]);
location.reload();
});
const term_element = document.querySelector('#terminal');
const term = new xterm.Terminal();
term.options.scrollback = 0;
term.open(term_element);
const fit_addon = new xterm_addon_fit.FitAddon();
const webgl_addon = new xterm_addon_webgl.WebglAddon();
term.loadAddon(webgl_addon);
term.loadAddon(fit_addon);
const stdin_buffer = [];
const stdout_buffer = [];
const stderr_buffer = [];
const stdin = () => {
return stdin_buffer.shift() || 0;
}
const stdout = code => {
if (code == 0) {
term.write(new Uint8Array(stdout_buffer));
stdout_buffer.length = 0;
} else {
stdout_buffer.push(code)
}
}
const stderr = code => {
if (code == 0 || code == 10) {
console.error(String.fromCodePoint(...stderr_buffer));
stderr_buffer = [];
} else {
stderr_buffer.push(code)
}
}
const onBinary = e => {
for(const c of e)
stdin_buffer.push(c.charCodeAt(0));
}
term.onBinary(onBinary);
term.onData(onBinary)
term.resize(140,43);
window.Module = {
preRun: () => {
FS.init(stdin, stdout, stderr);
},
postRun: [],
onRuntimeInitialized: () => {
if (window.Module._ftxui_on_resize == undefined)
return;
fit_addon.fit();
const resize_handler = () => {
const {cols, rows} = fit_addon.proposeDimensions();
term.resize(cols, rows);
window.Module._ftxui_on_resize(cols, rows);
fit_addon.fit();
};
const resize_observer = new ResizeObserver(resize_handler);
resize_observer.observe(term_element);
resize_handler();
// Disable scrollbar
//term.write('\x1b[?47h')
},
};
const words = example.split('/')
words[1] = "ftxui_example_" + words[1] + ".js"
document.querySelector("#example_script").src = words.join('/');

30
flake.lock generated
View File

@@ -1,12 +1,15 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1678901627,
"narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
@@ -17,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1679734080,
"narHash": "sha256-z846xfGLlon6t9lqUzlNtBOmsgQLQIZvR6Lt2dImk1M=",
"lastModified": 1697915759,
"narHash": "sha256-WyMj5jGcecD+KC8gEs+wFth1J1wjisZf8kVZH13f1Zo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "dbf5322e93bcc6cfc52268367a8ad21c09d76fea",
"rev": "51d906d2341c9e866e48c2efcaac0f2d70bfd43e",
"type": "github"
},
"original": {
@@ -36,6 +39,21 @@
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View File

@@ -8,9 +8,11 @@
outputs = {self, nixpkgs, flake-utils}:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = import nixpkgs { inherit system; }; in
{
packages.ftxui = pkgs.stdenv.mkDerivation rec {
let pkgs = import nixpkgs { inherit system; }; in
let llvm = pkgs.llvmPackages_latest; in
{
packages = rec {
default = pkgs.stdenv.mkDerivation rec {
pname = "ftxui";
version = "v4.0.0";
src = pkgs.fetchFromGitHub {
@@ -56,6 +58,19 @@
platforms = pkgs.lib.platforms.all;
};
};
}
);
ftxui = default;
};
devShells = {
default = pkgs.mkShell {
nativeBuildInputs = [
pkgs.cmake
pkgs.clang-tools
llvm.clang
];
};
};
}
);
}

View File

@@ -44,6 +44,7 @@ class ComponentBase {
ComponentBase* Parent() const;
Component& ChildAt(size_t i);
size_t ChildCount() const;
int Index() const;
void Add(Component children);
void Detach();
void DetachAllChildren();

View File

@@ -25,6 +25,7 @@ struct EntryState {
bool state; ///< The state of the button/checkbox/radiobox
bool active; ///< Whether the entry is the active one.
bool focused; ///< Whether the entry is one focused by the user.
int index; ///< Index of the entry when applicable or -1.
};
struct UnderlineOption {

View File

@@ -22,7 +22,7 @@ using Elements = std::vector<Element>;
class Node {
public:
Node();
Node(Elements children);
explicit Node(Elements children);
Node(const Node&) = delete;
Node(const Node&&) = delete;
Node& operator=(const Node&) = delete;

View File

@@ -36,8 +36,8 @@ class TableSelection;
class Table {
public:
Table();
Table(std::vector<std::vector<std::string>>);
Table(std::vector<std::vector<Element>>);
explicit Table(std::vector<std::vector<std::string>>);
explicit Table(std::vector<std::vector<Element>>);
Table(std::initializer_list<std::vector<std::string>> init);
TableSelection SelectAll();
TableSelection SelectCell(int column, int row);

View File

@@ -48,11 +48,8 @@ class ButtonBase : public ComponentBase, public ButtonOption {
}
auto focus_management = focused ? focus : active ? select : nothing;
const EntryState state = {
*label,
false,
active,
focused_or_hover,
const EntryState state{
*label, false, active, focused_or_hover, Index(),
};
auto element = (transform ? transform : DefaultTransform) //

View File

@@ -28,10 +28,7 @@ class CheckboxBase : public ComponentBase, public CheckboxOption {
const bool is_active = Active();
auto focus_management = is_focused ? focus : is_active ? select : nothing;
auto entry_state = EntryState{
*label,
*checked,
is_active,
is_focused || hovered_,
*label, *checked, is_active, is_focused || hovered_, -1,
};
auto element = (transform ? transform : CheckboxOption::Simple().transform)(
entry_state);

View File

@@ -51,6 +51,22 @@ size_t ComponentBase::ChildCount() const {
return children_.size();
}
/// @brief Return index of the component in its parent. -1 if no parent.
/// @ingroup component
int ComponentBase::Index() const {
if (parent_ == nullptr) {
return -1;
}
int index = 0;
for (const Component& child : parent_->children_) {
if (child.get() == this) {
return index;
}
index++;
}
return -1; // Not reached.
}
/// @brief Add a child.
/// @@param child The child to be attached.
/// @ingroup component

View File

@@ -123,10 +123,7 @@ class MenuBase : public ComponentBase, public MenuOption {
const bool is_selected = (selected() == i);
const EntryState state = {
entries[i],
false,
is_selected,
is_focused,
entries[i], false, is_selected, is_focused, i,
};
auto focus_management = (selected_focus_ != i) ? nothing
@@ -625,11 +622,8 @@ Component MenuEntry(MenuEntryOption option) {
const bool focused = Focused();
UpdateAnimationTarget();
const EntryState state = {
label(),
false,
hovered_,
focused,
const EntryState state{
label(), false, hovered_, focused, Index(),
};
const Element element =

View File

@@ -226,5 +226,50 @@ TEST(MenuTest, AnimationsVertical) {
}
}
TEST(MenuTest, EntryIndex) {
int selected = 0;
std::vector<std::string> entries = {"0", "1", "2"};
auto option = MenuOption::Vertical();
option.entries = &entries;
option.selected = &selected;
option.entries_option.transform = [&](const EntryState& state) {
int curidx = std::stoi(state.label);
EXPECT_EQ(state.index, curidx);
return text(state.label);
};
auto menu = Menu(option);
menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::Return);
entries.resize(2);
(void)menu->Render();
}
TEST(MenuTest, MenuEntryIndex) {
int selected = 0;
MenuEntryOption option;
option.transform = [&](const EntryState& state) {
int curidx = std::stoi(state.label);
EXPECT_EQ(state.index, curidx);
return text(state.label);
};
auto menu = Container::Vertical(
{
MenuEntry("0", option),
MenuEntry("1", option),
MenuEntry("2", option),
},
&selected);
menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::Return);
for (int index = 0; index < menu->ChildCount(); index++) {
EXPECT_EQ(menu->ChildAt(index)->Index(), index);
}
}
} // namespace ftxui
// NOLINTEND

View File

@@ -40,10 +40,7 @@ class RadioboxBase : public ComponentBase, public RadioboxOption {
: is_menu_focused ? focus
: select;
auto state = EntryState{
entries[i],
selected() == i,
is_selected,
is_focused,
entries[i], selected() == i, is_selected, is_focused, i,
};
auto element =
(transform ? transform : RadioboxOption::Simple().transform)(state);

View File

@@ -93,7 +93,7 @@ class ResizeDecorator : public NodeDecorator {
Element DefaultRenderState(const WindowRenderState& state) {
Element element = state.inner;
if (state.active) {
if (!state.active) {
element |= dim;
}