mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-28 16:29:34 +08:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4188ee2c04 | ||
![]() |
026a005753 | ||
![]() |
7298636e7c | ||
![]() |
5e199fcd85 | ||
![]() |
57a5512a22 | ||
![]() |
75482d82d4 | ||
![]() |
31c26c6956 | ||
![]() |
6dd626a79a | ||
![]() |
05fc866d74 | ||
![]() |
46f481ded7 | ||
![]() |
75cd2b0fca | ||
![]() |
0a5e9f2a2f | ||
![]() |
66cdf9b2a5 | ||
![]() |
84287eb217 | ||
![]() |
535974d291 | ||
![]() |
753502998c | ||
![]() |
31b5fac9c5 | ||
![]() |
76b2f17488 | ||
![]() |
c5ef0c7fb5 |
161
.github/workflows/build.yaml
vendored
Normal file
161
.github/workflows/build.yaml
vendored
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
create:
|
||||||
|
tags:
|
||||||
|
-v*
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: "Tests"
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: Linux GCC
|
||||||
|
os: ubuntu-latest
|
||||||
|
compiler: g++-9
|
||||||
|
test: true
|
||||||
|
|
||||||
|
- name: Linux Clang
|
||||||
|
os: ubuntu-latest
|
||||||
|
compiler: clang++
|
||||||
|
test: true
|
||||||
|
|
||||||
|
- name: MacOS clang
|
||||||
|
os: macos-latest
|
||||||
|
compiler: clang++
|
||||||
|
test: true
|
||||||
|
|
||||||
|
- name: Windows MSVC
|
||||||
|
os: windows-latest
|
||||||
|
compiler: cl
|
||||||
|
test: false
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: "Checkout repository"
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: "Enable MSVC command prompt"
|
||||||
|
if: matrix.os == 'windows-latest'
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
|
||||||
|
- name: "Install cmake"
|
||||||
|
uses: lukka/get-cmake@latest
|
||||||
|
|
||||||
|
- name: "Build debug mode"
|
||||||
|
run: >
|
||||||
|
mkdir build;
|
||||||
|
cd build;
|
||||||
|
cmake ..
|
||||||
|
-DCMAKE_CXX_COMPILER=${{ matrix.compiler }}
|
||||||
|
-DFTXUI_BUILD_DOCS=OFF
|
||||||
|
-DFTXUI_BUILD_EXAMPLES=ON
|
||||||
|
-DFTXUI_BUILD_TESTS=ON
|
||||||
|
-DFTXUI_BUILD_TESTS_FUZZER=OFF
|
||||||
|
-DFTXUI_ENABLE_INSTALL=ON ;
|
||||||
|
cmake --build . --config Debug;
|
||||||
|
|
||||||
|
- name: "Run tests"
|
||||||
|
if: matrix.test
|
||||||
|
run: >
|
||||||
|
cd build;
|
||||||
|
./tests
|
||||||
|
|
||||||
|
# Create a release on new v* tags
|
||||||
|
release:
|
||||||
|
needs: test
|
||||||
|
if: ${{ github.event_name == 'create' && startsWith(github.ref, 'refs/tags/v') }}
|
||||||
|
name: "Create release"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
steps:
|
||||||
|
- name: "Create release"
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
id: create_release
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Build artifact for the release
|
||||||
|
package:
|
||||||
|
name: "Build packages"
|
||||||
|
needs: release
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
asset_path: build/ftxui*Linux*
|
||||||
|
- os: macos-latest
|
||||||
|
asset_path: build/ftxui*Darwin*
|
||||||
|
- os: windows-latest
|
||||||
|
asset_path: build/ftxui*Win64*
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: "Checkout repository"
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: "Install cmake"
|
||||||
|
uses: lukka/get-cmake@latest
|
||||||
|
|
||||||
|
- name: "Build packages"
|
||||||
|
run: >
|
||||||
|
mkdir build;
|
||||||
|
cd build;
|
||||||
|
cmake ..
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
-DFTXUI_BUILD_DOCS=OFF
|
||||||
|
-DFTXUI_BUILD_EXAMPLES=OFF
|
||||||
|
-DFTXUI_BUILD_TESTS=OFF
|
||||||
|
-DFTXUI_BUILD_TESTS_FUZZER=OFF
|
||||||
|
-DFTXUI_ENABLE_INSTALL=ON;
|
||||||
|
cmake --build . --target package;
|
||||||
|
- uses: shogo82148/actions-upload-release-asset@v1
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.release.outputs.upload_url }}
|
||||||
|
asset_path: ${{ matrix.asset_path }}
|
||||||
|
overwrite: true
|
||||||
|
|
||||||
|
documentation:
|
||||||
|
needs: package
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "Checkout repository"
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: "Install cmake"
|
||||||
|
uses: lukka/get-cmake@latest
|
||||||
|
|
||||||
|
- name: "Install emsdk"
|
||||||
|
uses: mymindstorm/setup-emsdk@v7
|
||||||
|
|
||||||
|
- name: "Install Doxygen/Graphviz"
|
||||||
|
run: >
|
||||||
|
sudo apt-get update;
|
||||||
|
sudo apt-get install doxygen graphviz;
|
||||||
|
|
||||||
|
- name: "Build documentation"
|
||||||
|
run: >
|
||||||
|
mkdir build;
|
||||||
|
cd build;
|
||||||
|
emcmake cmake ..;
|
||||||
|
cmake --build . --target doc;
|
||||||
|
rsync -amv --include='*/' --include='*.html' --include='*.js' --include='*.wasm' --exclude='*' examples doc/doxygen/html;
|
||||||
|
|
||||||
|
- name: "Deploy"
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: build/doc/doxygen/html/
|
||||||
|
enable_jekyll: false
|
||||||
|
allow_empty_commit: false
|
||||||
|
force_orphan: true
|
||||||
|
publish_branch: gh-pages
|
71
.github/workflows/codeql-analysis.yml
vendored
71
.github/workflows/codeql-analysis.yml
vendored
@@ -1,71 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ master ]
|
|
||||||
schedule:
|
|
||||||
- cron: '38 7 * * 4'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'cpp' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
|
||||||
# Learn more:
|
|
||||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v1
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v1
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 https://git.io/JvXDl
|
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
||||||
# and modify them (or add more) to build your code if your project
|
|
||||||
# uses a compiled language
|
|
||||||
|
|
||||||
#- run: |
|
|
||||||
# make bootstrap
|
|
||||||
# make release
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v1
|
|
27
.github/workflows/linux-clang.yaml
vendored
27
.github/workflows/linux-clang.yaml
vendored
@@ -1,27 +0,0 @@
|
|||||||
name: Linux Clang
|
|
||||||
|
|
||||||
on:
|
|
||||||
- pull_request
|
|
||||||
- push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Linux Clang
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
|
||||||
- name: Build
|
|
||||||
run: >
|
|
||||||
mkdir build;
|
|
||||||
cd build;
|
|
||||||
cmake ..
|
|
||||||
-DCMAKE_CXX_COMPILER=clang++
|
|
||||||
-DFTXUI_BUILD_TESTS=ON;
|
|
||||||
cmake --build . --config Release;
|
|
||||||
|
|
||||||
- name: Tests
|
|
||||||
if: ${{ matrix.config.test }}
|
|
||||||
run: >
|
|
||||||
cd build;
|
|
||||||
./tests
|
|
47
.github/workflows/linux-emscripten.yaml
vendored
47
.github/workflows/linux-emscripten.yaml
vendored
@@ -1,47 +0,0 @@
|
|||||||
name: Linux Emscripten
|
|
||||||
|
|
||||||
on:
|
|
||||||
- pull_request
|
|
||||||
- push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Linux Emscripten
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
DOCUMENTATION: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
|
||||||
- uses: mymindstorm/setup-emsdk@v7
|
|
||||||
|
|
||||||
- name: Install Doxygen/Graphviz
|
|
||||||
if: fromJSON(env.DOCUMENTATION)
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install doxygen graphviz
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
emcmake cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -S . -B build
|
|
||||||
cmake --build build
|
|
||||||
|
|
||||||
- name: Build documentation
|
|
||||||
if: fromJSON(env.DOCUMENTATION)
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
cmake --build . --target doc
|
|
||||||
# Copy emscripten built examples to the doxygen output directory for deployment
|
|
||||||
rsync -amv --include='*/' --include='*.html' --include='*.js' --include='*.wasm' --exclude='*' examples doc/doxygen/html
|
|
||||||
|
|
||||||
# Deploy the HTML documentation to GitHub Pages
|
|
||||||
- name: GH Pages Deployment
|
|
||||||
if: fromJSON(env.DOCUMENTATION)
|
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
publish_dir: build/doc/doxygen/html/
|
|
||||||
enable_jekyll: false
|
|
||||||
allow_empty_commit: false
|
|
||||||
force_orphan: true
|
|
||||||
publish_branch: gh-pages
|
|
26
.github/workflows/linux-gcc.yaml
vendored
26
.github/workflows/linux-gcc.yaml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: Linux GCC
|
|
||||||
|
|
||||||
on:
|
|
||||||
- pull_request
|
|
||||||
- push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Linux GCC
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
|
||||||
- name: Build
|
|
||||||
run: >
|
|
||||||
mkdir build;
|
|
||||||
cd build;
|
|
||||||
cmake ..
|
|
||||||
-DCMAKE_CXX_COMPILER=g++-9
|
|
||||||
-DFTXUI_BUILD_TESTS=ON;
|
|
||||||
cmake --build . --config Release;
|
|
||||||
|
|
||||||
- name: Tests
|
|
||||||
run: >
|
|
||||||
cd build;
|
|
||||||
./tests
|
|
27
.github/workflows/mac-clang.yaml
vendored
27
.github/workflows/mac-clang.yaml
vendored
@@ -1,27 +0,0 @@
|
|||||||
name: MacOS Clang
|
|
||||||
|
|
||||||
on:
|
|
||||||
- pull_request
|
|
||||||
- push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: MacOS Clang
|
|
||||||
runs-on: macos-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
|
||||||
- name: Build
|
|
||||||
run: >
|
|
||||||
mkdir build;
|
|
||||||
cd build;
|
|
||||||
cmake ..
|
|
||||||
-DCMAKE_CXX_COMPILER=clang++
|
|
||||||
-DFTXUI_BUILD_TESTS=ON;
|
|
||||||
cmake --build . --config Release;
|
|
||||||
|
|
||||||
- name: Tests
|
|
||||||
if: ${{ matrix.config.test }}
|
|
||||||
run: >
|
|
||||||
cd build;
|
|
||||||
./tests
|
|
28
.github/workflows/windows-msvc.yaml
vendored
28
.github/workflows/windows-msvc.yaml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: Windows MSVC
|
|
||||||
|
|
||||||
on:
|
|
||||||
- pull_request
|
|
||||||
- push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Windows MSVC
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
|
||||||
- uses: ilammy/msvc-dev-cmd@v1
|
|
||||||
- name: Build
|
|
||||||
run: >
|
|
||||||
mkdir build;
|
|
||||||
cd build;
|
|
||||||
cmake ..
|
|
||||||
-DCMAKE_CXX_COMPILER="cl"
|
|
||||||
-DFTXUI_BUILD_TESTS=ON;
|
|
||||||
cmake --build . --config Release;
|
|
||||||
|
|
||||||
- name: Tests
|
|
||||||
if: ${{ matrix.config.test }}
|
|
||||||
run: >
|
|
||||||
cd build;
|
|
||||||
./tests.exe
|
|
40
CHANGELOG.md
40
CHANGELOG.md
@@ -1,6 +1,42 @@
|
|||||||
# Changelog
|
Changelog
|
||||||
|
=========
|
||||||
|
|
||||||
## 0.9 (2021-09-26)
|
released (development)
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
0.11
|
||||||
|
----
|
||||||
|
|
||||||
|
## github workflow
|
||||||
|
- Add Windows ad MacOS artefacts.
|
||||||
|
- Merge all the workflows.
|
||||||
|
|
||||||
|
## Bug
|
||||||
|
- On Unix system, fallback to {80,25} screen dimension on failure.
|
||||||
|
|
||||||
|
## CMake
|
||||||
|
- Support for shared library, via `BUILD_SHARED_LIBS` option.
|
||||||
|
- Add library version and symlinks.
|
||||||
|
|
||||||
|
0.10 (2021-09-30)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
## Bug
|
||||||
|
- Fix the automated merge of borders.
|
||||||
|
|
||||||
|
### Dom
|
||||||
|
- `Table()` class to build stylised table.
|
||||||
|
See https://github.com/ArthurSonzogni/FTXUI/discussions/228
|
||||||
|
- `vscroll_indicator`. Show a scrollbar indicator on the right.
|
||||||
|
- `separatorEmpty`. A separator drawing nothing.
|
||||||
|
- `separatorFixed`. A separator drawing the provided character.
|
||||||
|
|
||||||
|
### Component
|
||||||
|
- `Maybe`: Display an component conditionnally based on a boolean.
|
||||||
|
- `Dropdown`: A dropdown select list.
|
||||||
|
|
||||||
|
0.9 (2021-09-26)
|
||||||
|
----------------
|
||||||
|
|
||||||
The initial release where changelog where written.
|
The initial release where changelog where written.
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ include(cmake/ftxui_git_version.cmake)
|
|||||||
|
|
||||||
project(ftxui
|
project(ftxui
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
VERSION 0.9.${git_version}
|
VERSION 0.11.${git_version}
|
||||||
)
|
)
|
||||||
|
|
||||||
option(FTXUI_BUILD_DOCS "Set to ON to build tests" ON)
|
option(FTXUI_BUILD_DOCS "Set to ON to build tests" ON)
|
||||||
@@ -24,7 +24,7 @@ else()
|
|||||||
${FTXUI_MICROSOFT_TERMINAL_FALLBACK_HELP_TEXT} OFF)
|
${FTXUI_MICROSOFT_TERMINAL_FALLBACK_HELP_TEXT} OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(screen STATIC
|
add_library(screen
|
||||||
src/ftxui/screen/box.cpp
|
src/ftxui/screen/box.cpp
|
||||||
src/ftxui/screen/color.cpp
|
src/ftxui/screen/color.cpp
|
||||||
src/ftxui/screen/color_info.cpp
|
src/ftxui/screen/color_info.cpp
|
||||||
@@ -38,7 +38,7 @@ add_library(screen STATIC
|
|||||||
include/ftxui/screen/string.hpp
|
include/ftxui/screen/string.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(dom STATIC
|
add_library(dom
|
||||||
include/ftxui/dom/elements.hpp
|
include/ftxui/dom/elements.hpp
|
||||||
include/ftxui/dom/node.hpp
|
include/ftxui/dom/node.hpp
|
||||||
include/ftxui/dom/requirement.hpp
|
include/ftxui/dom/requirement.hpp
|
||||||
@@ -57,24 +57,26 @@ add_library(dom STATIC
|
|||||||
src/ftxui/dom/frame.cpp
|
src/ftxui/dom/frame.cpp
|
||||||
src/ftxui/dom/gauge.cpp
|
src/ftxui/dom/gauge.cpp
|
||||||
src/ftxui/dom/graph.cpp
|
src/ftxui/dom/graph.cpp
|
||||||
src/ftxui/dom/hbox.cpp
|
|
||||||
src/ftxui/dom/gridbox.cpp
|
src/ftxui/dom/gridbox.cpp
|
||||||
|
src/ftxui/dom/hbox.cpp
|
||||||
src/ftxui/dom/hflow.cpp
|
src/ftxui/dom/hflow.cpp
|
||||||
src/ftxui/dom/inverted.cpp
|
src/ftxui/dom/inverted.cpp
|
||||||
src/ftxui/dom/node.cpp
|
src/ftxui/dom/node.cpp
|
||||||
src/ftxui/dom/node_decorator.cpp
|
src/ftxui/dom/node_decorator.cpp
|
||||||
src/ftxui/dom/paragraph.cpp
|
src/ftxui/dom/paragraph.cpp
|
||||||
src/ftxui/dom/reflect.cpp
|
src/ftxui/dom/reflect.cpp
|
||||||
|
src/ftxui/dom/scroll_indicator.cpp
|
||||||
src/ftxui/dom/separator.cpp
|
src/ftxui/dom/separator.cpp
|
||||||
src/ftxui/dom/size.cpp
|
src/ftxui/dom/size.cpp
|
||||||
src/ftxui/dom/spinner.cpp
|
src/ftxui/dom/spinner.cpp
|
||||||
|
src/ftxui/dom/table.cpp
|
||||||
src/ftxui/dom/text.cpp
|
src/ftxui/dom/text.cpp
|
||||||
src/ftxui/dom/underlined.cpp
|
src/ftxui/dom/underlined.cpp
|
||||||
src/ftxui/dom/util.cpp
|
src/ftxui/dom/util.cpp
|
||||||
src/ftxui/dom/vbox.cpp
|
src/ftxui/dom/vbox.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(component STATIC
|
add_library(component
|
||||||
include/ftxui/component/captured_mouse.hpp
|
include/ftxui/component/captured_mouse.hpp
|
||||||
include/ftxui/component/component.hpp
|
include/ftxui/component/component.hpp
|
||||||
include/ftxui/component/component_base.hpp
|
include/ftxui/component/component_base.hpp
|
||||||
@@ -87,8 +89,10 @@ add_library(component STATIC
|
|||||||
src/ftxui/component/checkbox.cpp
|
src/ftxui/component/checkbox.cpp
|
||||||
src/ftxui/component/component.cpp
|
src/ftxui/component/component.cpp
|
||||||
src/ftxui/component/container.cpp
|
src/ftxui/component/container.cpp
|
||||||
|
src/ftxui/component/dropdown.cpp
|
||||||
src/ftxui/component/event.cpp
|
src/ftxui/component/event.cpp
|
||||||
src/ftxui/component/input.cpp
|
src/ftxui/component/input.cpp
|
||||||
|
src/ftxui/component/maybe.cpp
|
||||||
src/ftxui/component/menu.cpp
|
src/ftxui/component/menu.cpp
|
||||||
src/ftxui/component/radiobox.cpp
|
src/ftxui/component/radiobox.cpp
|
||||||
src/ftxui/component/radiobox.cpp
|
src/ftxui/component/radiobox.cpp
|
||||||
@@ -108,9 +112,13 @@ target_link_libraries(dom
|
|||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
target_link_libraries(component
|
target_link_libraries(component
|
||||||
PUBLIC dom
|
PUBLIC dom
|
||||||
PRIVATE Threads::Threads
|
PUBLIC Threads::Threads
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(screen PROPERTIES VERSION ${PROJECT_VERSION})
|
||||||
|
set_target_properties(dom PROPERTIES VERSION ${PROJECT_VERSION})
|
||||||
|
set_target_properties(component PROPERTIES VERSION ${PROJECT_VERSION})
|
||||||
|
|
||||||
include(cmake/ftxui_set_options.cmake)
|
include(cmake/ftxui_set_options.cmake)
|
||||||
ftxui_set_options(screen)
|
ftxui_set_options(screen)
|
||||||
ftxui_set_options(dom)
|
ftxui_set_options(dom)
|
||||||
@@ -120,10 +128,6 @@ if (FTXUI_BUILD_TESTS AND ${CMAKE_VERSION} VERSION_GREATER "3.11.4")
|
|||||||
include(cmake/ftxui_test.cmake)
|
include(cmake/ftxui_test.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(FTXUI_ENABLE_INSTALL)
|
|
||||||
include(cmake/ftxui_install.cmake)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(FTXUI_BUILD_EXAMPLES)
|
if(FTXUI_BUILD_EXAMPLES)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
@@ -134,3 +138,8 @@ endif()
|
|||||||
|
|
||||||
include(cmake/iwyu.cmake)
|
include(cmake/iwyu.cmake)
|
||||||
include(cmake/ftxui_export.cmake)
|
include(cmake/ftxui_export.cmake)
|
||||||
|
|
||||||
|
if(FTXUI_ENABLE_INSTALL)
|
||||||
|
include(cmake/ftxui_install.cmake)
|
||||||
|
include(cmake/ftxui_package.cmake)
|
||||||
|
endif()
|
||||||
|
61
README.md
61
README.md
@@ -1,24 +1,29 @@
|
|||||||
# FTXUI
|
<p align="center">
|
||||||
|
<img src="./examples/component/homescreen.gif" alt="Demo image"></img>
|
||||||
|
<br/>
|
||||||
|
<a href="#"><img src="https://img.shields.io/badge/c++-%2300599C.svg?style=flat&logo=c%2B%2B&logoColor=white"></img></a>
|
||||||
|
<a href="http://opensource.org/licenses/MIT"><img src="https://img.shields.io/github/license/arthursonzogni/FTXUI?color=black"></img></a>
|
||||||
|
<a href="#"><img src="https://img.shields.io/github/stars/ArthurSonzogni/FTXUI"></img></a>
|
||||||
|
<a href="#"><img src="https://img.shields.io/github/forks/ArthurSonzogni/FTXUI"></img></a>
|
||||||
|
<a href="#"><img src="https://img.shields.io/github/repo-size/ArthurSonzogni/FTXUI"></img></a>
|
||||||
|
<a href="https://github.com/ArthurSonzogni/FTXUI/issues"><img src="https://img.shields.io/github/issues/ArthurSonzogni/FTXUI"></img></a>
|
||||||
|
<a href="https://github.com/ArthurSonzogni/FTXUI/graphs/contributors"><img src="https://img.shields.io/github/contributors/arthursonzogni/FTXUI?color=blue"></img></a>
|
||||||
|
|
||||||
[![issues][badge.issues]][issues]
|
<br/>
|
||||||
[![license][badge.license]][license]
|
<a href="https://arthursonzogni.github.io/FTXUI/">Documentation</a> ·
|
||||||
[![contributors][badge.contributors]][contributors]
|
<a href="https://github.com/ArthurSonzogni/FTXUI/issues">Report Bug</a> ·
|
||||||
|
<a href="https://arthursonzogni.github.io/FTXUI/examples.html">Examples</a> .
|
||||||
|
<a href="https://github.com/ArthurSonzogni/FTXUI/issues">Request Feature</a> ·
|
||||||
|
<a href="https://github.com/ArthurSonzogni/FTXUI/pulls">Send a Pull Request</a>
|
||||||
|
|
||||||
[badge.issues]: https://img.shields.io/github/issues-raw/arthursonzogni/FTXUI
|
</p>
|
||||||
[badge.license]: https://img.shields.io/github/license/arthursonzogni/FTXUI?color=black
|
|
||||||
[badge.contributors]: https://img.shields.io/github/contributors/arthursonzogni/FTXUI?color=blue
|
|
||||||
|
|
||||||
[issues]: https://github.com/ArthurSonzogni/FTXUI/issues
|
## FTXUI
|
||||||
[license]: http://opensource.org/licenses/MIT
|
|
||||||
[contributors]: https://github.com/ArthurSonzogni/FTXUI/graphs/contributors
|
|
||||||
|
|
||||||
**Functional Terminal (X) User interface**
|
<i>Functional Terminal (X) User interface</i>
|
||||||
|
|
||||||
A simple C++ library for terminal based user interface.
|
A simple C++ library for terminal based user interface.
|
||||||
|
|
||||||
## Demo:
|
|
||||||

|
|
||||||
|
|
||||||
## Feature
|
## Feature
|
||||||
* Functional style. Inspired by
|
* Functional style. Inspired by
|
||||||
[[1]](https://hackernoon.com/building-reactive-terminal-interfaces-in-c-d392ce34e649?gi=d9fb9ce35901)
|
[[1]](https://hackernoon.com/building-reactive-terminal-interfaces-in-c-d392ce34e649?gi=d9fb9ce35901)
|
||||||
@@ -30,25 +35,13 @@ A simple C++ library for terminal based user interface.
|
|||||||
* Keyboard & mouse navigation.
|
* Keyboard & mouse navigation.
|
||||||
|
|
||||||
## Operating systems
|
## Operating systems
|
||||||
- [![linux-emscripten][badge.linux-emscripten]][link.linux-emscripten]
|
|
||||||
- [![linux-gcc][badge.linux-gcc]][link.linux-gcc]
|
|
||||||
[![linux-clang][badge.linux-clang]][link.linux-clang]
|
|
||||||
- [![windows-msvc][badge.windows-msvc]][link.windows-msvc]
|
|
||||||
- [![mac-clang][badge.mac-clang]][link.mac-clang]
|
|
||||||
|
|
||||||
[badge.linux-gcc]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-gcc.yaml/badge.svg?branch=master
|
- Webassembly
|
||||||
[badge.linux-clang]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-clang.yaml/badge.svg?branch=master
|
- Linux
|
||||||
[badge.linux-emscripten]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-emscripten.yaml/badge.svg?branch=master
|
- MacOS
|
||||||
[badge.windows-msvc]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/windows-msvc.yaml/badge.svg?branch=master
|
- Windows
|
||||||
[badge.mac-clang]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/mac-clang.yaml/badge.svg?branch=master
|
|
||||||
|
|
||||||
[link.linux-gcc]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-gcc.yaml
|
## Example
|
||||||
[link.linux-clang]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-clang.yaml
|
|
||||||
[link.linux-emscripten]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-emscripten.yaml
|
|
||||||
[link.windows-msvc]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/windows-msvc.yaml
|
|
||||||
[link.mac-clang]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/mac-clang.yaml
|
|
||||||
|
|
||||||
## Example:
|
|
||||||
~~~cpp
|
~~~cpp
|
||||||
vbox({
|
vbox({
|
||||||
hbox({
|
hbox({
|
||||||
@@ -69,7 +62,7 @@ A simple C++ library for terminal based user interface.
|
|||||||
└────────────────────────────────────────────────────────────────────────────┘
|
└────────────────────────────────────────────────────────────────────────────┘
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
# Documentation:
|
# Documentation
|
||||||
|
|
||||||
- [Starter example project](https://github.com/ArthurSonzogni/ftxui-starter)
|
- [Starter example project](https://github.com/ArthurSonzogni/ftxui-starter)
|
||||||
- [Documentation](https://arthursonzogni.github.io/FTXUI/)
|
- [Documentation](https://arthursonzogni.github.io/FTXUI/)
|
||||||
@@ -94,11 +87,11 @@ Feel free to add your projects here:
|
|||||||
- [todoman](https://github.com/aaleino/todoman)
|
- [todoman](https://github.com/aaleino/todoman)
|
||||||
- [TimeAccumulator](https://github.com/asari555/TimeAccumulator)
|
- [TimeAccumulator](https://github.com/asari555/TimeAccumulator)
|
||||||
|
|
||||||
## Hosted on:
|
## Hosted on
|
||||||
* [github](https://github.com/ArthurSonzogni/ftxui)
|
* [github](https://github.com/ArthurSonzogni/ftxui)
|
||||||
* [gitlab](https://gitlab.com/ArthurSonzogni/ftxui)
|
* [gitlab](https://gitlab.com/ArthurSonzogni/ftxui)
|
||||||
|
|
||||||
## External package:
|
## External package
|
||||||
|
|
||||||
It is **highly** recommanded to use cmake FetchContent to depends on FTXUI. This
|
It is **highly** recommanded to use cmake FetchContent to depends on FTXUI. This
|
||||||
way you can specify which commit you would like to depends on.
|
way you can specify which commit you would like to depends on.
|
||||||
|
24
cmake/ftxui_package.cmake
Normal file
24
cmake/ftxui_package.cmake
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
if (UNIX AND NOT APPLE)
|
||||||
|
set(CPACK_GENERATOR "DEB;External;RPM;STGZ;TBZ2;TGZ;TXZ;TZ;TZST;ZIP")
|
||||||
|
elseif (UNIX AND APPLE)
|
||||||
|
set(CPACK_GENERATOR "DragNDrop;NuGet;TGZ;ZIP")
|
||||||
|
elseif (WIN32)
|
||||||
|
set(CPACK_GENERATOR "DEB;NuGet;TGZ;ZIP")
|
||||||
|
else()
|
||||||
|
set(CPACK_GENERATOR "ZIP")
|
||||||
|
endif()
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS " ")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE_URL "https://github.com/ArthurSonzogni/FTXUI/")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Arthur Sonzogni")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||||
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A simple C++ Terminal UI library")
|
||||||
|
set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/ArthurSonzogni/FTXUI/")
|
||||||
|
set(CPACK_PACKAGE_NAME "ftxui")
|
||||||
|
set(CPACK_PACKAGE_VENDOR "Arthur Sonzogni")
|
||||||
|
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||||
|
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||||
|
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||||
|
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||||
|
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||||
|
|
||||||
|
include(CPack)
|
@@ -20,6 +20,7 @@ add_executable(tests
|
|||||||
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/gauge_test.cpp
|
src/ftxui/dom/gauge_test.cpp
|
||||||
|
src/ftxui/dom/table_test.cpp
|
||||||
src/ftxui/dom/gridbox_test.cpp
|
src/ftxui/dom/gridbox_test.cpp
|
||||||
src/ftxui/dom/hbox_test.cpp
|
src/ftxui/dom/hbox_test.cpp
|
||||||
src/ftxui/dom/text_test.cpp
|
src/ftxui/dom/text_test.cpp
|
||||||
|
@@ -2,19 +2,21 @@ set(DIRECTORY_LIB component)
|
|||||||
|
|
||||||
example(button)
|
example(button)
|
||||||
example(checkbox)
|
example(checkbox)
|
||||||
example(nested_screen)
|
|
||||||
example(checkbox_in_frame)
|
example(checkbox_in_frame)
|
||||||
example(composition)
|
example(composition)
|
||||||
|
example(dropdown)
|
||||||
example(gallery)
|
example(gallery)
|
||||||
example(homescreen)
|
example(homescreen)
|
||||||
example(input)
|
example(input)
|
||||||
|
example(maybe)
|
||||||
example(menu)
|
example(menu)
|
||||||
example(menu_in_frame)
|
|
||||||
example(menu2)
|
example(menu2)
|
||||||
example(menu_multiple)
|
|
||||||
example(menu_entries)
|
example(menu_entries)
|
||||||
|
example(menu_in_frame)
|
||||||
|
example(menu_multiple)
|
||||||
example(menu_style)
|
example(menu_style)
|
||||||
example(modal_dialog)
|
example(modal_dialog)
|
||||||
|
example(nested_screen)
|
||||||
example(print_key_press)
|
example(print_key_press)
|
||||||
example(radiobox)
|
example(radiobox)
|
||||||
example(radiobox_in_frame)
|
example(radiobox_in_frame)
|
||||||
|
@@ -24,7 +24,8 @@ int main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto renderer = Renderer(container, [&] {
|
auto renderer = Renderer(container, [&] {
|
||||||
return container->Render() | frame | size(HEIGHT, LESS_THAN, 10) | border;
|
return container->Render() | vscroll_indicator | frame |
|
||||||
|
size(HEIGHT, LESS_THAN, 10) | border;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FitComponent();
|
auto screen = ScreenInteractive::FitComponent();
|
||||||
|
45
examples/component/dropdown.cpp
Normal file
45
examples/component/dropdown.cpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#include <string> // for basic_string, string, allocator
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "ftxui/component/captured_mouse.hpp" // for ftxui
|
||||||
|
#include "ftxui/component/component.hpp" // for Dropdown, Horizontal, Vertical
|
||||||
|
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
using namespace ftxui;
|
||||||
|
|
||||||
|
std::vector<std::string> entries = {
|
||||||
|
"tribute", "clearance", "ally", "bend", "electronics",
|
||||||
|
"module", "era", "cultural", "sniff", "nationalism",
|
||||||
|
"negotiation", "deliver", "figure", "east", "tribute",
|
||||||
|
"clearance", "ally", "bend", "electronics", "module",
|
||||||
|
"era", "cultural", "sniff", "nationalism", "negotiation",
|
||||||
|
"deliver", "figure", "east", "tribute", "clearance",
|
||||||
|
"ally", "bend", "electronics", "module", "era",
|
||||||
|
"cultural", "sniff", "nationalism", "negotiation", "deliver",
|
||||||
|
"figure", "east",
|
||||||
|
};
|
||||||
|
|
||||||
|
int selected_1 = 0;
|
||||||
|
int selected_2 = 0;
|
||||||
|
int selected_3 = 0;
|
||||||
|
int selected_4 = 0;
|
||||||
|
|
||||||
|
auto layout = Container::Vertical({
|
||||||
|
Container::Horizontal({
|
||||||
|
Dropdown(&entries, &selected_1),
|
||||||
|
Dropdown(&entries, &selected_2),
|
||||||
|
}),
|
||||||
|
Container::Horizontal({
|
||||||
|
Dropdown(&entries, &selected_3),
|
||||||
|
Dropdown(&entries, &selected_4),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto screen = ScreenInteractive::FitComponent();
|
||||||
|
screen.Loop(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
@@ -214,23 +214,25 @@ int main(int argc, const char* argv[]) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto compiler_renderer = Renderer(compiler_component, [&] {
|
auto compiler_renderer = Renderer(compiler_component, [&] {
|
||||||
auto compiler_win = window(text("Compiler"), compiler->Render() | frame);
|
auto compiler_win = window(text("Compiler"),
|
||||||
auto flags_win = window(text("Flags"), flags->Render() | frame);
|
compiler->Render() | vscroll_indicator | frame);
|
||||||
|
auto flags_win =
|
||||||
|
window(text("Flags"), flags->Render() | vscroll_indicator | frame);
|
||||||
auto executable_win = window(text("Executable:"), executable_->Render());
|
auto executable_win = window(text("Executable:"), executable_->Render());
|
||||||
auto input_win =
|
auto input_win =
|
||||||
window(text("Input"),
|
window(text("Input"), hbox({
|
||||||
hbox({
|
vbox({
|
||||||
vbox({
|
hbox({
|
||||||
hbox({
|
text("Add: "),
|
||||||
text("Add: "),
|
input_add->Render(),
|
||||||
input_add->Render(),
|
}) | size(WIDTH, EQUAL, 20) |
|
||||||
}) | size(WIDTH, EQUAL, 20) |
|
size(HEIGHT, EQUAL, 1),
|
||||||
size(HEIGHT, EQUAL, 1),
|
filler(),
|
||||||
filler(),
|
}),
|
||||||
}),
|
separator(),
|
||||||
separator(),
|
input->Render() | vscroll_indicator | frame |
|
||||||
input->Render() | frame | size(HEIGHT, EQUAL, 3) | flex,
|
size(HEIGHT, EQUAL, 3) | flex,
|
||||||
}));
|
}));
|
||||||
return vbox({
|
return vbox({
|
||||||
hbox({
|
hbox({
|
||||||
compiler_win,
|
compiler_win,
|
||||||
@@ -240,7 +242,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
input_win | size(WIDTH, EQUAL, 60),
|
input_win | size(WIDTH, EQUAL, 60),
|
||||||
}),
|
}),
|
||||||
filler(),
|
filler(),
|
||||||
}) | size(HEIGHT, LESS_THAN, 6),
|
}) | size(HEIGHT, LESS_THAN, 8),
|
||||||
hflow(render_command()) | flex_grow,
|
hflow(render_command()) | flex_grow,
|
||||||
}) |
|
}) |
|
||||||
flex_grow | border;
|
flex_grow | border;
|
||||||
|
46
examples/component/maybe.cpp
Normal file
46
examples/component/maybe.cpp
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include <memory> // for shared_ptr, __shared_ptr_access
|
||||||
|
#include <string> // for string, basic_string, allocator
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "ftxui/component/captured_mouse.hpp" // for ftxui
|
||||||
|
#include "ftxui/component/component.hpp" // for Checkbox, Maybe, Radiobox, Renderer, Vertical
|
||||||
|
#include "ftxui/component/component_base.hpp" // for ComponentBase
|
||||||
|
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
|
||||||
|
#include "ftxui/dom/elements.hpp" // for Element, operator|, border
|
||||||
|
|
||||||
|
using namespace ftxui;
|
||||||
|
Component Border(Component child) {
|
||||||
|
return Renderer(child, [child] { return child->Render() | border; });
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
std::vector<std::string> entries = {
|
||||||
|
"entry 1",
|
||||||
|
"entry 2",
|
||||||
|
"entry 3",
|
||||||
|
};
|
||||||
|
int menu_1_selected = 0;
|
||||||
|
int menu_2_selected = 0;
|
||||||
|
auto menu_1 = Radiobox(&entries, &menu_1_selected);
|
||||||
|
auto menu_2 = Radiobox(&entries, &menu_2_selected);
|
||||||
|
|
||||||
|
menu_1 = Border(menu_1);
|
||||||
|
menu_2 = Border(menu_2);
|
||||||
|
|
||||||
|
bool menu_1_show = false;
|
||||||
|
bool menu_2_show = false;
|
||||||
|
|
||||||
|
auto layout = Container::Vertical({
|
||||||
|
Checkbox("Show menu_1", &menu_1_show),
|
||||||
|
Maybe(menu_1, &menu_1_show),
|
||||||
|
Checkbox("Show menu_2", &menu_2_show),
|
||||||
|
Maybe(menu_2, &menu_2_show),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto screen = ScreenInteractive::TerminalOutput();
|
||||||
|
screen.Loop(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
@@ -18,7 +18,8 @@ int main(int argc, const char* argv[]) {
|
|||||||
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() | frame | size(HEIGHT, LESS_THAN, 10) | border;
|
return radiobox->Render() | vscroll_indicator | frame |
|
||||||
|
size(HEIGHT, LESS_THAN, 10) | border;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FitComponent();
|
auto screen = ScreenInteractive::FitComponent();
|
||||||
|
@@ -18,7 +18,8 @@ int main(int argc, const char* argv[]) {
|
|||||||
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() | frame | size(HEIGHT, LESS_THAN, 10) | border;
|
return radiobox->Render() | vscroll_indicator | frame |
|
||||||
|
size(HEIGHT, LESS_THAN, 10) | border;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FitComponent();
|
auto screen = ScreenInteractive::FitComponent();
|
||||||
|
@@ -3,9 +3,13 @@ set(DIRECTORY_LIB dom)
|
|||||||
example(border)
|
example(border)
|
||||||
example(border_style)
|
example(border_style)
|
||||||
example(color_gallery)
|
example(color_gallery)
|
||||||
|
example(color_info_palette256)
|
||||||
|
example(color_truecolor_HSV)
|
||||||
|
example(color_truecolor_RGB)
|
||||||
example(dbox)
|
example(dbox)
|
||||||
example(gauge)
|
example(gauge)
|
||||||
example(graph)
|
example(graph)
|
||||||
|
example(gridbox)
|
||||||
example(hflow)
|
example(hflow)
|
||||||
example(html_like)
|
example(html_like)
|
||||||
example(package_manager)
|
example(package_manager)
|
||||||
@@ -17,13 +21,10 @@ example(spinner)
|
|||||||
example(style_blink)
|
example(style_blink)
|
||||||
example(style_bold)
|
example(style_bold)
|
||||||
example(style_color)
|
example(style_color)
|
||||||
example(color_truecolor_RGB)
|
|
||||||
example(color_truecolor_HSV)
|
|
||||||
example(color_info_palette256)
|
|
||||||
example(style_dim)
|
example(style_dim)
|
||||||
example(gridbox)
|
|
||||||
example(style_gallery)
|
example(style_gallery)
|
||||||
example(style_inverted)
|
example(style_inverted)
|
||||||
example(style_underlined)
|
example(style_underlined)
|
||||||
|
example(table)
|
||||||
example(vbox_hbox)
|
example(vbox_hbox)
|
||||||
example(window)
|
example(window)
|
||||||
|
66
examples/dom/table.cpp
Normal file
66
examples/dom/table.cpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#include <ftxui/dom/elements.hpp> // for color, Fit, LIGHT, align_right, bold, DOUBLE
|
||||||
|
#include <ftxui/dom/table.hpp> // for Table, TableSelection
|
||||||
|
#include <ftxui/screen/screen.hpp> // for Screen
|
||||||
|
#include <iostream> // for endl, cout, ostream
|
||||||
|
#include <string> // for basic_string, allocator, string
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "ftxui/dom/node.hpp" // for Render
|
||||||
|
#include "ftxui/screen/box.hpp" // for ftxui
|
||||||
|
#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Cyan, Color::White
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
using namespace ftxui;
|
||||||
|
|
||||||
|
auto table = Table({
|
||||||
|
{"Version", "Marketing name", "Release date", "API level", "Runtime"},
|
||||||
|
{"2.3", "Gingerbread", "February 9 2011", "10", "Dalvik 1.4.0"},
|
||||||
|
{"4.0", "Ice Cream Sandwich", "October 19 2011", "15", "Dalvik"},
|
||||||
|
{"4.1", "Jelly Bean", "July 9 2012", "16", "Dalvik"},
|
||||||
|
{"4.2", "Jelly Bean", "November 13 2012", "17", "Dalvik"},
|
||||||
|
{"4.3", "Jelly Bean", "July 24 2013", "18", "Dalvik"},
|
||||||
|
{"4.4", "KitKat", "October 31 2013", "19", "Dalvik and ART"},
|
||||||
|
{"5.0", "Lollipop", "November 3 2014", "21", "ART"},
|
||||||
|
{"5.1", "Lollipop", "March 9 2015", "22", "ART"},
|
||||||
|
{"6.0", "Marshmallow", "October 5 2015", "23", "ART"},
|
||||||
|
{"7.0", "Nougat", "August 22 2016", "24", "ART"},
|
||||||
|
{"7.1", "Nougat", "October 4 2016", "25", "ART"},
|
||||||
|
{"8.0", "Oreo", "August 21 2017", "26", "ART"},
|
||||||
|
{"8.1", "Oreo", "December 5 2017", "27", "ART"},
|
||||||
|
{"9", "Pie", "August 6 2018", "28", "ART"},
|
||||||
|
{"10", "10", "September 3 2019", "29", "ART"},
|
||||||
|
{"11", "11", "September 8 2020", "30", "ART"},
|
||||||
|
});
|
||||||
|
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
|
||||||
|
// Add border around the first column.
|
||||||
|
table.SelectColumn(0).Border(LIGHT);
|
||||||
|
|
||||||
|
// Make first row bold with a double border.
|
||||||
|
table.SelectRow(0).Decorate(bold);
|
||||||
|
table.SelectRow(0).SeparatorVertical(LIGHT);
|
||||||
|
table.SelectRow(0).Border(DOUBLE);
|
||||||
|
|
||||||
|
// Align right the "Release date" column.
|
||||||
|
table.SelectColumn(2).DecorateCells(align_right);
|
||||||
|
|
||||||
|
// Select row from the second to the last.
|
||||||
|
auto content = table.SelectRows(1, -1);
|
||||||
|
// Alternate in between 3 colors.
|
||||||
|
content.DecorateCellsAlternateRow(color(Color::Blue), 3, 0);
|
||||||
|
content.DecorateCellsAlternateRow(color(Color::Cyan), 3, 1);
|
||||||
|
content.DecorateCellsAlternateRow(color(Color::White), 3, 2);
|
||||||
|
|
||||||
|
auto document = table.Render();
|
||||||
|
auto screen = Screen::Create(Dimension::Fit(document));
|
||||||
|
Render(screen, document);
|
||||||
|
screen.Print();
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
@@ -39,6 +39,7 @@ Component Menu(ConstStringListRef entries,
|
|||||||
int* selected_,
|
int* selected_,
|
||||||
Ref<MenuOption> = {});
|
Ref<MenuOption> = {});
|
||||||
Component MenuEntry(ConstStringRef label, Ref<MenuEntryOption> = {});
|
Component MenuEntry(ConstStringRef label, Ref<MenuEntryOption> = {});
|
||||||
|
Component Dropdown(ConstStringListRef entries, int* selected);
|
||||||
Component Radiobox(ConstStringListRef entries,
|
Component Radiobox(ConstStringListRef entries,
|
||||||
int* selected_,
|
int* selected_,
|
||||||
Ref<RadioboxOption> option = {});
|
Ref<RadioboxOption> option = {});
|
||||||
@@ -55,6 +56,7 @@ Component Renderer(Component child, std::function<Element()>);
|
|||||||
Component Renderer(std::function<Element()>);
|
Component Renderer(std::function<Element()>);
|
||||||
Component Renderer(std::function<Element(bool /* focused */)>);
|
Component Renderer(std::function<Element(bool /* focused */)>);
|
||||||
Component CatchEvent(Component child, std::function<bool(Event)>);
|
Component CatchEvent(Component child, std::function<bool(Event)>);
|
||||||
|
Component Maybe(Component, bool* show);
|
||||||
|
|
||||||
namespace Container {
|
namespace Container {
|
||||||
Component Vertical(Components children);
|
Component Vertical(Components children);
|
||||||
|
@@ -74,6 +74,8 @@ struct Event {
|
|||||||
bool operator!=(const Event& other) const { return !operator==(other); }
|
bool operator!=(const Event& other) const { return !operator==(other); }
|
||||||
|
|
||||||
//--- State section ----------------------------------------------------------
|
//--- State section ----------------------------------------------------------
|
||||||
|
ScreenInteractive* screen_ = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend ComponentBase;
|
friend ComponentBase;
|
||||||
friend ScreenInteractive;
|
friend ScreenInteractive;
|
||||||
@@ -95,8 +97,6 @@ struct Event {
|
|||||||
struct Cursor cursor_;
|
struct Cursor cursor_;
|
||||||
};
|
};
|
||||||
std::string input_;
|
std::string input_;
|
||||||
|
|
||||||
ScreenInteractive* screen_ = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@@ -17,7 +17,7 @@ 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)>;
|
||||||
|
|
||||||
enum BorderStyle { LIGHT, HEAVY, DOUBLE, ROUNDED };
|
enum BorderStyle { LIGHT, HEAVY, DOUBLE, ROUNDED, EMPTY };
|
||||||
|
|
||||||
// Pipe elements into decorator togethers.
|
// Pipe elements into decorator togethers.
|
||||||
// For instance the next lines are equivalents:
|
// For instance the next lines are equivalents:
|
||||||
@@ -34,20 +34,24 @@ Element separator(void);
|
|||||||
Element separatorLight();
|
Element separatorLight();
|
||||||
Element separatorHeavy();
|
Element separatorHeavy();
|
||||||
Element separatorDouble();
|
Element separatorDouble();
|
||||||
|
Element separatorEmpty();
|
||||||
Element separatorStyled(BorderStyle);
|
Element separatorStyled(BorderStyle);
|
||||||
Element separator(Pixel);
|
Element separator(Pixel);
|
||||||
|
Element separatorCharacter(std::string);
|
||||||
Element gauge(float ratio);
|
Element gauge(float ratio);
|
||||||
Element border(Element);
|
Element border(Element);
|
||||||
Element borderLight(Element);
|
Element borderLight(Element);
|
||||||
Element borderHeavy(Element);
|
Element borderHeavy(Element);
|
||||||
Element borderDouble(Element);
|
Element borderDouble(Element);
|
||||||
Element borderRounded(Element);
|
Element borderRounded(Element);
|
||||||
|
Element borderEmpty(Element);
|
||||||
Decorator borderStyled(BorderStyle);
|
Decorator borderStyled(BorderStyle);
|
||||||
Decorator borderWith(Pixel);
|
Decorator borderWith(Pixel);
|
||||||
Element window(Element title, Element content);
|
Element window(Element title, Element content);
|
||||||
Element spinner(int charset_index, size_t image_index);
|
Element spinner(int charset_index, size_t image_index);
|
||||||
Elements paragraph(std::string text); // Use inside hflow(). Split by space.
|
Elements paragraph(std::string text); // Use inside hflow(). Split by space.
|
||||||
Element graph(GraphFunction);
|
Element graph(GraphFunction);
|
||||||
|
Element emptyElement();
|
||||||
|
|
||||||
// -- Decorator ---
|
// -- Decorator ---
|
||||||
Element bold(Element);
|
Element bold(Element);
|
||||||
@@ -104,6 +108,8 @@ Element yframe(Element);
|
|||||||
Element focus(Element);
|
Element focus(Element);
|
||||||
Element select(Element);
|
Element select(Element);
|
||||||
|
|
||||||
|
Element vscroll_indicator(Element);
|
||||||
|
|
||||||
// --- Util --------------------------------------------------------------------
|
// --- Util --------------------------------------------------------------------
|
||||||
Element hcenter(Element);
|
Element hcenter(Element);
|
||||||
Element vcenter(Element);
|
Element vcenter(Element);
|
||||||
|
93
include/ftxui/dom/table.hpp
Normal file
93
include/ftxui/dom/table.hpp
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#ifndef FTXUI_DOM_TABLE
|
||||||
|
#define FTXUI_DOM_TABLE
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string> // for string
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "ftxui/dom/elements.hpp" // for BorderStyle, LIGHT, Element, Decorator
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// Initialization:
|
||||||
|
// ---------------
|
||||||
|
//
|
||||||
|
// auto table = Table({
|
||||||
|
// {"X", "Y"},
|
||||||
|
// {"-1", "1"},
|
||||||
|
// {"+0", "0"},
|
||||||
|
// {"+1", "1"},
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// table.SelectAll().Border(LIGHT);
|
||||||
|
//
|
||||||
|
// table.SelectRow(1).Border(DOUBLE);
|
||||||
|
// table.SelectRow(1).SeparatorInternal(Light);
|
||||||
|
//
|
||||||
|
// std::move(table).Element();
|
||||||
|
|
||||||
|
class Table;
|
||||||
|
class TableSelection;
|
||||||
|
|
||||||
|
class Table {
|
||||||
|
public:
|
||||||
|
Table(std::vector<std::vector<std::string>>);
|
||||||
|
TableSelection SelectAll();
|
||||||
|
TableSelection SelectCell(int column, int row);
|
||||||
|
TableSelection SelectRow(int row_index);
|
||||||
|
TableSelection SelectRows(int row_min, int row_max);
|
||||||
|
TableSelection SelectColumn(int column_index);
|
||||||
|
TableSelection SelectColumns(int column_min, int column_max);
|
||||||
|
TableSelection SelectRectangle(int column_min,
|
||||||
|
int column_max,
|
||||||
|
int row_min,
|
||||||
|
int row_max);
|
||||||
|
Element Render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend TableSelection;
|
||||||
|
std::vector<std::vector<Element>> elements_;
|
||||||
|
int input_dim_x_;
|
||||||
|
int input_dim_y_;
|
||||||
|
int dim_x_;
|
||||||
|
int dim_y_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TableSelection {
|
||||||
|
public:
|
||||||
|
void Decorate(Decorator);
|
||||||
|
void DecorateAlternateRow(Decorator, int modulo = 2, int shift = 0);
|
||||||
|
void DecorateAlternateColumn(Decorator, int modulo = 2, int shift = 0);
|
||||||
|
|
||||||
|
void DecorateCells(Decorator);
|
||||||
|
void DecorateCellsAlternateColumn(Decorator, int modulo = 2, int shift = 0);
|
||||||
|
void DecorateCellsAlternateRow(Decorator, int modulo = 2, int shift = 0);
|
||||||
|
|
||||||
|
void Border(BorderStyle border = LIGHT);
|
||||||
|
void BorderLeft(BorderStyle border = LIGHT);
|
||||||
|
void BorderRight(BorderStyle border = LIGHT);
|
||||||
|
void BorderTop(BorderStyle border = LIGHT);
|
||||||
|
void BorderBottom(BorderStyle border = LIGHT);
|
||||||
|
|
||||||
|
void Separator(BorderStyle border = LIGHT);
|
||||||
|
void SeparatorVertical(BorderStyle border = LIGHT);
|
||||||
|
void SeparatorHorizontal(BorderStyle border = LIGHT);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend Table;
|
||||||
|
Table* table_;
|
||||||
|
int x_min_;
|
||||||
|
int x_max_;
|
||||||
|
int y_min_;
|
||||||
|
int y_max_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_DOM_TABLE */
|
||||||
|
|
||||||
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
@@ -9,6 +9,7 @@ struct Dimensions {
|
|||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
Dimensions Size();
|
Dimensions Size();
|
||||||
|
void SetFallbackSize(const Dimensions& fallbackSize);
|
||||||
|
|
||||||
enum Color {
|
enum Color {
|
||||||
Palette1,
|
Palette1,
|
||||||
|
@@ -57,7 +57,7 @@ Component GeneratorComponent(const char*& data, size_t& size, int depth) {
|
|||||||
if (depth <= 0)
|
if (depth <= 0)
|
||||||
return Button(GeneratorString(data, size), [] {});
|
return Button(GeneratorString(data, size), [] {});
|
||||||
|
|
||||||
switch (value % 16) {
|
switch (value % 18) {
|
||||||
case 1:
|
case 1:
|
||||||
return Checkbox(GeneratorString(data, size), &g_bool);
|
return Checkbox(GeneratorString(data, size), &g_bool);
|
||||||
case 2:
|
case 2:
|
||||||
@@ -102,6 +102,10 @@ Component GeneratorComponent(const char*& data, size_t& size, int depth) {
|
|||||||
&g_int);
|
&g_int);
|
||||||
case 15:
|
case 15:
|
||||||
return Container::Tab(GeneratorComponents(data, size, depth - 1), &g_int);
|
return Container::Tab(GeneratorComponents(data, size, depth - 1), &g_int);
|
||||||
|
case 16:
|
||||||
|
return Maybe(GeneratorComponent(data, size, depth - 1), &g_bool);
|
||||||
|
case 17:
|
||||||
|
return Dropdown(&g_list, &g_int);
|
||||||
default:
|
default:
|
||||||
return Button(GeneratorString(data, size), [] {});
|
return Button(GeneratorString(data, size), [] {});
|
||||||
}
|
}
|
||||||
|
64
src/ftxui/component/dropdown.cpp
Normal file
64
src/ftxui/component/dropdown.cpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#include <memory> // for __shared_ptr_access
|
||||||
|
#include <string> // for string
|
||||||
|
#include <utility> // for move
|
||||||
|
|
||||||
|
#include "ftxui/component/component.hpp" // for Maybe, Checkbox, Make, Radiobox, Vertical, Dropdown
|
||||||
|
#include "ftxui/component/component_base.hpp" // for Component, ComponentBase
|
||||||
|
#include "ftxui/component/component_options.hpp" // for CheckboxOption
|
||||||
|
#include "ftxui/dom/elements.hpp" // for operator|, Element, border, filler, separator, size, vbox, frame, vscroll_indicator, HEIGHT, LESS_THAN
|
||||||
|
#include "ftxui/util/ref.hpp" // for ConstStringListRef
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
|
||||||
|
Component Dropdown(ConstStringListRef entries, int* selected) {
|
||||||
|
class Impl : public ComponentBase {
|
||||||
|
public:
|
||||||
|
Impl(ConstStringListRef entries, int* selected)
|
||||||
|
: entries_(std::move(entries)), selected_(selected) {
|
||||||
|
CheckboxOption option;
|
||||||
|
option.style_checked = "↓│";
|
||||||
|
option.style_unchecked = "→│";
|
||||||
|
checkbox_ = Checkbox(&title_, &show_, option),
|
||||||
|
radiobox_ = Radiobox(entries_, selected_);
|
||||||
|
|
||||||
|
Add(Container::Vertical({
|
||||||
|
checkbox_,
|
||||||
|
Maybe(radiobox_, &show_),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Element Render() override {
|
||||||
|
title_ = entries_[*selected_];
|
||||||
|
if (show_) {
|
||||||
|
return vbox({
|
||||||
|
checkbox_->Render(),
|
||||||
|
separator(),
|
||||||
|
radiobox_->Render() | vscroll_indicator | frame |
|
||||||
|
size(HEIGHT, LESS_THAN, 12),
|
||||||
|
}) |
|
||||||
|
border;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vbox({
|
||||||
|
checkbox_->Render() | border,
|
||||||
|
filler(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConstStringListRef entries_;
|
||||||
|
bool show_ = false;
|
||||||
|
int* selected_;
|
||||||
|
std::string title_;
|
||||||
|
Component checkbox_;
|
||||||
|
Component radiobox_;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Make<Impl>(std::move(entries), selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
40
src/ftxui/component/maybe.cpp
Normal file
40
src/ftxui/component/maybe.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include <memory> // for make_unique, __shared_ptr_access, __shared_ptr_access<>::element_type, shared_ptr
|
||||||
|
#include <utility> // for move
|
||||||
|
|
||||||
|
#include "ftxui/component/component.hpp" // for Make, Maybe
|
||||||
|
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component
|
||||||
|
#include "ftxui/component/event.hpp" // for Event
|
||||||
|
#include "ftxui/dom/elements.hpp" // for Element
|
||||||
|
#include "ftxui/dom/node.hpp" // for Node
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
|
||||||
|
Component Maybe(Component child, bool* show) {
|
||||||
|
class Impl : public ComponentBase {
|
||||||
|
public:
|
||||||
|
Impl(bool* show) : show_(show) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Element Render() override {
|
||||||
|
return *show_ ? ComponentBase::Render() : std::make_unique<Node>();
|
||||||
|
}
|
||||||
|
bool Focusable() const override {
|
||||||
|
return *show_ && ComponentBase::Focusable();
|
||||||
|
}
|
||||||
|
bool OnEvent(Event event) override {
|
||||||
|
return *show_ && ComponentBase::OnEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool* show_;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto maybe = Make<Impl>(show);
|
||||||
|
maybe->Add(std::move(child));
|
||||||
|
return maybe;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
30
src/ftxui/component/show.cpp
Normal file
30
src/ftxui/component/show.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "ftxui/component/component_base.hpp"
|
||||||
|
|
||||||
|
Component Maybe(Component child, bool* show) {
|
||||||
|
class Impl : public ComponentBase {
|
||||||
|
public:
|
||||||
|
Impl(Component child, bool* show) : ComponentBase(child), show_(show) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Element Render() override {
|
||||||
|
if (*show_)
|
||||||
|
return ComponentBase::Render();
|
||||||
|
else
|
||||||
|
return text("");
|
||||||
|
}
|
||||||
|
bool Focusable() const override {
|
||||||
|
return *show_ && ComponentBase::Focusable();
|
||||||
|
}
|
||||||
|
bool OnEvent(Event event) override {
|
||||||
|
if (*show_)
|
||||||
|
return false return ComponentBase::OnEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool* show_;
|
||||||
|
};
|
||||||
|
return Make<Impl>(std::move(child), show);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
@@ -14,10 +14,11 @@
|
|||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
static std::string simple_border_charset[6][6] = {
|
static std::string simple_border_charset[6][6] = {
|
||||||
{"┌", "┐", "└", "┘", "─", "│"},
|
{"┌", "┐", "└", "┘", "─", "│"}, //
|
||||||
{"┏", "┓", "┗", "┛", "━", "┃"},
|
{"┏", "┓", "┗", "┛", "━", "┃"}, //
|
||||||
{"╔", "╗", "╚", "╝", "═", "║"},
|
{"╔", "╗", "╚", "╝", "═", "║"}, //
|
||||||
{"╭", "╮", "╰", "╯", "─", "│"},
|
{"╭", "╮", "╰", "╯", "─", "│"}, //
|
||||||
|
{" ", " ", " ", " ", " ", " "}, //
|
||||||
};
|
};
|
||||||
|
|
||||||
// For reference, here is the charset for normal border:
|
// For reference, here is the charset for normal border:
|
||||||
@@ -124,6 +125,7 @@ class Border : public Node {
|
|||||||
/// @see borderLight
|
/// @see borderLight
|
||||||
/// @see borderDouble
|
/// @see borderDouble
|
||||||
/// @see borderHeavy
|
/// @see borderHeavy
|
||||||
|
/// @see borderEmpty
|
||||||
/// @see borderRounded
|
/// @see borderRounded
|
||||||
///
|
///
|
||||||
/// Add a border around an element
|
/// Add a border around an element
|
||||||
@@ -174,6 +176,7 @@ Decorator borderStyled(BorderStyle style) {
|
|||||||
/// @see borderDouble
|
/// @see borderDouble
|
||||||
/// @see borderHeavy
|
/// @see borderHeavy
|
||||||
/// @see borderRounded
|
/// @see borderRounded
|
||||||
|
/// @see borderEmpty
|
||||||
/// @see borderStyled
|
/// @see borderStyled
|
||||||
/// @see borderWith
|
/// @see borderWith
|
||||||
///
|
///
|
||||||
@@ -192,9 +195,9 @@ Decorator borderStyled(BorderStyle style) {
|
|||||||
/// ### Output
|
/// ### Output
|
||||||
///
|
///
|
||||||
/// ```bash
|
/// ```bash
|
||||||
/// ┌──────────────┐
|
/// ┌──────────────┐
|
||||||
/// │The element │
|
/// │The element │
|
||||||
/// └──────────────┘
|
/// └──────────────┘
|
||||||
/// ```
|
/// ```
|
||||||
Element borderLight(Element child) {
|
Element borderLight(Element child) {
|
||||||
return std::make_shared<Border>(unpack(std::move(child)), LIGHT);
|
return std::make_shared<Border>(unpack(std::move(child)), LIGHT);
|
||||||
@@ -207,6 +210,7 @@ Element borderLight(Element child) {
|
|||||||
/// @see borderDouble
|
/// @see borderDouble
|
||||||
/// @see borderHeavy
|
/// @see borderHeavy
|
||||||
/// @see borderRounded
|
/// @see borderRounded
|
||||||
|
/// @see borderEmpty
|
||||||
/// @see borderStyled
|
/// @see borderStyled
|
||||||
/// @see borderWith
|
/// @see borderWith
|
||||||
///
|
///
|
||||||
@@ -225,9 +229,9 @@ Element borderLight(Element child) {
|
|||||||
/// ### Output
|
/// ### Output
|
||||||
///
|
///
|
||||||
/// ```bash
|
/// ```bash
|
||||||
/// ┏━━━━━━━━━━━━━━┓
|
/// ┏━━━━━━━━━━━━━━┓
|
||||||
/// ┃The element ┃
|
/// ┃The element ┃
|
||||||
/// ┗━━━━━━━━━━━━━━┛
|
/// ┗━━━━━━━━━━━━━━┛
|
||||||
/// ```
|
/// ```
|
||||||
Element borderHeavy(Element child) {
|
Element borderHeavy(Element child) {
|
||||||
return std::make_shared<Border>(unpack(std::move(child)), HEAVY);
|
return std::make_shared<Border>(unpack(std::move(child)), HEAVY);
|
||||||
@@ -240,6 +244,7 @@ Element borderHeavy(Element child) {
|
|||||||
/// @see borderDouble
|
/// @see borderDouble
|
||||||
/// @see borderHeavy
|
/// @see borderHeavy
|
||||||
/// @see borderRounded
|
/// @see borderRounded
|
||||||
|
/// @see borderEmpty
|
||||||
/// @see borderStyled
|
/// @see borderStyled
|
||||||
/// @see borderWith
|
/// @see borderWith
|
||||||
///
|
///
|
||||||
@@ -258,9 +263,9 @@ Element borderHeavy(Element child) {
|
|||||||
/// ### Output
|
/// ### Output
|
||||||
///
|
///
|
||||||
/// ```bash
|
/// ```bash
|
||||||
/// ╔══════════════╗
|
/// ╔══════════════╗
|
||||||
/// ║The element ║
|
/// ║The element ║
|
||||||
/// ╚══════════════╝
|
/// ╚══════════════╝
|
||||||
/// ```
|
/// ```
|
||||||
Element borderDouble(Element child) {
|
Element borderDouble(Element child) {
|
||||||
return std::make_shared<Border>(unpack(std::move(child)), DOUBLE);
|
return std::make_shared<Border>(unpack(std::move(child)), DOUBLE);
|
||||||
@@ -273,6 +278,7 @@ Element borderDouble(Element child) {
|
|||||||
/// @see borderDouble
|
/// @see borderDouble
|
||||||
/// @see borderHeavy
|
/// @see borderHeavy
|
||||||
/// @see borderRounded
|
/// @see borderRounded
|
||||||
|
/// @see borderEmpty
|
||||||
/// @see borderStyled
|
/// @see borderStyled
|
||||||
/// @see borderWith
|
/// @see borderWith
|
||||||
///
|
///
|
||||||
@@ -291,14 +297,48 @@ Element borderDouble(Element child) {
|
|||||||
/// ### Output
|
/// ### Output
|
||||||
///
|
///
|
||||||
/// ```bash
|
/// ```bash
|
||||||
/// ╭──────────────╮
|
/// ╭──────────────╮
|
||||||
/// │The element │
|
/// │The element │
|
||||||
/// ╰──────────────╯
|
/// ╰──────────────╯
|
||||||
/// ```
|
/// ```
|
||||||
Element borderRounded(Element child) {
|
Element borderRounded(Element child) {
|
||||||
return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
|
return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Draw an empty border around the element.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see border
|
||||||
|
/// @see borderLight
|
||||||
|
/// @see borderDouble
|
||||||
|
/// @see borderHeavy
|
||||||
|
/// @see borderRounded
|
||||||
|
/// @see borderEmpty
|
||||||
|
/// @see borderStyled
|
||||||
|
/// @see borderWith
|
||||||
|
///
|
||||||
|
/// Add a border around an element
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'borderRounded' as a function...
|
||||||
|
/// Element document = borderRounded(text("The element"));
|
||||||
|
///
|
||||||
|
/// // ...Or as a 'pipe'.
|
||||||
|
/// Element document = text("The element") | borderRounded;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
///
|
||||||
|
/// The element
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
Element borderEmpty(Element child) {
|
||||||
|
return std::make_shared<Border>(unpack(std::move(child)), EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Draw window with a title and a border around the element.
|
/// @brief Draw window with a title and a border around the element.
|
||||||
/// @param title The title of the window.
|
/// @param title The title of the window.
|
||||||
/// @param content The element to be wrapped.
|
/// @param content The element to be wrapped.
|
||||||
|
@@ -10,7 +10,7 @@ namespace ftxui {
|
|||||||
/// @return The centered element.
|
/// @return The centered element.
|
||||||
/// @ingroup dom
|
/// @ingroup dom
|
||||||
Element hcenter(Element child) {
|
Element hcenter(Element child) {
|
||||||
return hbox(filler(), std::move(child), filler()) | xflex_grow;
|
return hbox(filler(), std::move(child), filler());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Center an element vertically.
|
/// @brief Center an element vertically.
|
||||||
@@ -18,7 +18,7 @@ Element hcenter(Element child) {
|
|||||||
/// @return The centered element.
|
/// @return The centered element.
|
||||||
/// @ingroup dom
|
/// @ingroup dom
|
||||||
Element vcenter(Element child) {
|
Element vcenter(Element child) {
|
||||||
return vbox(filler(), std::move(child), filler()) | yflex_grow;
|
return vbox(filler(), std::move(child), filler());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Center an element horizontally and vertically.
|
/// @brief Center an element horizontally and vertically.
|
||||||
@@ -26,7 +26,7 @@ Element vcenter(Element child) {
|
|||||||
/// @return The centered element.
|
/// @return The centered element.
|
||||||
/// @ingroup dom
|
/// @ingroup dom
|
||||||
Element center(Element child) {
|
Element center(Element child) {
|
||||||
return hcenter(vcenter(std::move(child))) | flex_grow;
|
return hcenter(vcenter(std::move(child)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Align an element on the right side.
|
/// @brief Align an element on the right side.
|
||||||
@@ -34,7 +34,7 @@ Element center(Element child) {
|
|||||||
/// @return The right aligned element.
|
/// @return The right aligned element.
|
||||||
/// @ingroup dom
|
/// @ingroup dom
|
||||||
Element align_right(Element child) {
|
Element align_right(Element child) {
|
||||||
return hbox(filler(), std::move(child)) | flex_grow;
|
return hbox(filler(), std::move(child));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
69
src/ftxui/dom/scroll_indicator.cpp
Normal file
69
src/ftxui/dom/scroll_indicator.cpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include <algorithm> // for max
|
||||||
|
#include <memory> // for make_shared, __shared_ptr_access
|
||||||
|
#include <string> // for string
|
||||||
|
#include <utility> // for move
|
||||||
|
#include <vector> // for __alloc_traits<>::value_type
|
||||||
|
|
||||||
|
#include "ftxui/dom/elements.hpp" // for Element, vscroll_indicator
|
||||||
|
#include "ftxui/dom/node.hpp" // for Node, Elements
|
||||||
|
#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator
|
||||||
|
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||||
|
#include "ftxui/screen/box.hpp" // for Box
|
||||||
|
#include "ftxui/screen/screen.hpp" // for Screen, Pixel
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
|
||||||
|
/// @brief Add a filter that will invert the foreground and the background
|
||||||
|
/// colors.
|
||||||
|
/// @ingroup dom
|
||||||
|
Element vscroll_indicator(Element child) {
|
||||||
|
class Impl : public NodeDecorator {
|
||||||
|
using NodeDecorator::NodeDecorator;
|
||||||
|
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
Node::ComputeRequirement();
|
||||||
|
requirement_ = children_[0]->requirement();
|
||||||
|
requirement_.min_x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBox(Box box) override {
|
||||||
|
Node::SetBox(box);
|
||||||
|
if (box_.x_min > box_.x_max)
|
||||||
|
box_.x_max--;
|
||||||
|
children_[0]->SetBox(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Screen& screen) final {
|
||||||
|
Node::Render(screen);
|
||||||
|
|
||||||
|
const Box& stencil = screen.stencil;
|
||||||
|
|
||||||
|
int size_inner = box_.y_max - box_.y_min;
|
||||||
|
int size_outter = stencil.y_max - stencil.y_min;
|
||||||
|
if (size_outter >= size_inner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int start_y = 2 * stencil.y_min + 2 * float(stencil.y_min - box_.y_min) *
|
||||||
|
(size_outter - 1) / size_inner;
|
||||||
|
int size = 2 * float(size_outter) * (size_outter - 1) / size_inner + 2;
|
||||||
|
size = std::max(size, 1);
|
||||||
|
|
||||||
|
const int x = stencil.x_max;
|
||||||
|
for (int y = stencil.y_min; y <= stencil.y_max; ++y) {
|
||||||
|
bool up = (2 * y + -1 >= start_y) && (2 * y - 1 <= start_y + size);
|
||||||
|
bool down = (2 * y - 0 >= start_y) && (2 * y - 0 <= start_y + size);
|
||||||
|
|
||||||
|
const char* c = up ? (down ? "┃" : "╹") : (down ? "╻" : " ");
|
||||||
|
screen.PixelAt(x, y).character = c;
|
||||||
|
screen.PixelAt(x, y).inverted = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return std::make_shared<Impl>(std::move(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
@@ -12,15 +12,36 @@ namespace ftxui {
|
|||||||
using ftxui::Screen;
|
using ftxui::Screen;
|
||||||
|
|
||||||
const std::string charset[][2] = {
|
const std::string charset[][2] = {
|
||||||
{"│", "─"},
|
{"│", "─"}, //
|
||||||
{"┃", "━"},
|
{"┃", "━"}, //
|
||||||
{"║", "═"},
|
{"║", "═"}, //
|
||||||
{"│", "─"},
|
{"│", "─"}, //
|
||||||
|
{" ", " "}, //
|
||||||
};
|
};
|
||||||
|
|
||||||
class Separator : public Node {
|
class Separator : public Node {
|
||||||
public:
|
public:
|
||||||
Separator(BorderStyle style) : style_(style) {}
|
Separator(std::string value) : value_(value) {}
|
||||||
|
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
requirement_.min_x = 1;
|
||||||
|
requirement_.min_y = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Screen& screen) override {
|
||||||
|
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||||
|
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||||
|
screen.PixelAt(x, y).character = value_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SeparatorAuto : public Node {
|
||||||
|
public:
|
||||||
|
SeparatorAuto(BorderStyle style) : style_(style) {}
|
||||||
|
|
||||||
void ComputeRequirement() override {
|
void ComputeRequirement() override {
|
||||||
requirement_.min_x = 1;
|
requirement_.min_x = 1;
|
||||||
@@ -43,9 +64,9 @@ class Separator : public Node {
|
|||||||
BorderStyle style_;
|
BorderStyle style_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SeparatorWithPixel : public Separator {
|
class SeparatorWithPixel : public SeparatorAuto {
|
||||||
public:
|
public:
|
||||||
SeparatorWithPixel(Pixel pixel) : Separator(LIGHT), pixel_(pixel) {}
|
SeparatorWithPixel(Pixel pixel) : SeparatorAuto(LIGHT), pixel_(pixel) {}
|
||||||
void Render(Screen& screen) override {
|
void Render(Screen& screen) override {
|
||||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||||
@@ -58,22 +79,288 @@ class SeparatorWithPixel : public Separator {
|
|||||||
Pixel pixel_;
|
Pixel pixel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Draw a vertical or horizontal separation in between two other
|
||||||
|
/// elements.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorEmpty
|
||||||
|
/// @see separatorRounded
|
||||||
|
/// @see separatorStyled
|
||||||
|
/// @see separatorCharacter
|
||||||
|
///
|
||||||
|
/// Add a visual separation in between two elements.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'border' as a function...
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("up"),
|
||||||
|
/// separator(),
|
||||||
|
/// text("down"),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// up
|
||||||
|
/// ────
|
||||||
|
/// down
|
||||||
|
/// ```
|
||||||
Element separator() {
|
Element separator() {
|
||||||
return std::make_shared<Separator>(LIGHT);
|
return std::make_shared<SeparatorAuto>(LIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Draw a vertical or horizontal separation in between two other
|
||||||
|
/// elements.
|
||||||
|
/// @param style the style of the separator.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorEmpty
|
||||||
|
/// @see separatorRounded
|
||||||
|
/// @see separatorStyled
|
||||||
|
/// @see separatorCharacter
|
||||||
|
///
|
||||||
|
/// Add a visual separation in between two elements.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'border' as a function...
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("up"),
|
||||||
|
/// separatorStyled(DOUBLE),
|
||||||
|
/// text("down"),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// up
|
||||||
|
/// ════
|
||||||
|
/// down
|
||||||
|
/// ```
|
||||||
Element separatorStyled(BorderStyle style) {
|
Element separatorStyled(BorderStyle style) {
|
||||||
return std::make_shared<Separator>(style);
|
return std::make_shared<SeparatorAuto>(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Draw a vertical or horizontal separation in between two other
|
||||||
|
/// elements, using the LIGHT style.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorEmpty
|
||||||
|
/// @see separatorRounded
|
||||||
|
/// @see separatorStyled
|
||||||
|
/// @see separatorCharacter
|
||||||
|
///
|
||||||
|
/// Add a visual separation in between two elements.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'border' as a function...
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("up"),
|
||||||
|
/// separatorLight(),
|
||||||
|
/// text("down"),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// up
|
||||||
|
/// ────
|
||||||
|
/// down
|
||||||
|
/// ```
|
||||||
Element separatorLight() {
|
Element separatorLight() {
|
||||||
return std::make_shared<Separator>(LIGHT);
|
return std::make_shared<SeparatorAuto>(LIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Draw a vertical or horizontal separation in between two other
|
||||||
|
/// elements, using the HEAVY style.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorEmpty
|
||||||
|
/// @see separatorRounded
|
||||||
|
/// @see separatorStyled
|
||||||
|
/// @see separatorCharacter
|
||||||
|
///
|
||||||
|
/// Add a visual separation in between two elements.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'border' as a function...
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("up"),
|
||||||
|
/// separatorHeavy(),
|
||||||
|
/// text("down"),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// up
|
||||||
|
/// ━━━━
|
||||||
|
/// down
|
||||||
|
/// ```
|
||||||
Element separatorHeavy() {
|
Element separatorHeavy() {
|
||||||
return std::make_shared<Separator>(HEAVY);
|
return std::make_shared<SeparatorAuto>(HEAVY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Draw a vertical or horizontal separation in between two other
|
||||||
|
/// elements, using the DOUBLE style.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorEmpty
|
||||||
|
/// @see separatorRounded
|
||||||
|
/// @see separatorStyled
|
||||||
|
/// @see separatorCharacter
|
||||||
|
///
|
||||||
|
/// Add a visual separation in between two elements.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'border' as a function...
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("up"),
|
||||||
|
/// separatorDouble(),
|
||||||
|
/// text("down"),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// up
|
||||||
|
/// ════
|
||||||
|
/// down
|
||||||
|
/// ```
|
||||||
Element separatorDouble() {
|
Element separatorDouble() {
|
||||||
return std::make_shared<Separator>(DOUBLE);
|
return std::make_shared<SeparatorAuto>(DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Draw a vertical or horizontal separation in between two other
|
||||||
|
/// elements, using the EMPTY style.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorEmpty
|
||||||
|
/// @see separatorRounded
|
||||||
|
/// @see separatorStyled
|
||||||
|
/// @see separatorCharacter
|
||||||
|
///
|
||||||
|
/// Add a visual separation in between two elements.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'border' as a function...
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("up"),
|
||||||
|
/// separator(),
|
||||||
|
/// text("down"),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// up
|
||||||
|
///
|
||||||
|
/// down
|
||||||
|
/// ```
|
||||||
|
Element separatorEmpty() {
|
||||||
|
return std::make_shared<SeparatorAuto>(EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Draw a vertical or horizontal separation in between two other
|
||||||
|
/// elements.
|
||||||
|
/// @param value the character to fill the separator area.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorEmpty
|
||||||
|
/// @see separatorRounded
|
||||||
|
/// @see separatorStyled
|
||||||
|
/// @see separatorCharacter
|
||||||
|
///
|
||||||
|
/// Add a visual separation in between two elements.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// // Use 'border' as a function...
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("up"),
|
||||||
|
/// separator(),
|
||||||
|
/// text("down"),
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// up
|
||||||
|
/// ────
|
||||||
|
/// down
|
||||||
|
/// ```
|
||||||
|
Element separatorCharacter(std::string value) {
|
||||||
|
return std::make_shared<Separator>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Draw a separator in between two element filled with a given pixel.
|
||||||
|
/// @ingroup dom
|
||||||
|
/// @see separator
|
||||||
|
/// @see separatorLight
|
||||||
|
/// @see separatorHeavy
|
||||||
|
/// @see separatorDouble
|
||||||
|
/// @see separatorStyled
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```cpp
|
||||||
|
/// Pixel empty;
|
||||||
|
/// Element document = vbox({
|
||||||
|
/// text("Up"),
|
||||||
|
/// separator(empty),
|
||||||
|
/// text("Down"),
|
||||||
|
/// })
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Output
|
||||||
|
///
|
||||||
|
/// ```bash
|
||||||
|
/// Up
|
||||||
|
///
|
||||||
|
/// Down
|
||||||
|
/// ```
|
||||||
|
Element separator(Pixel pixel) {
|
||||||
|
return std::make_shared<SeparatorWithPixel>(pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
295
src/ftxui/dom/table.cpp
Normal file
295
src/ftxui/dom/table.cpp
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
#include "ftxui/dom/table.hpp"
|
||||||
|
|
||||||
|
#include <algorithm> // for max
|
||||||
|
#include <memory> // for allocator, shared_ptr, allocator_traits<>::value_type
|
||||||
|
#include <utility> // for move, swap
|
||||||
|
|
||||||
|
#include "ftxui/dom/elements.hpp" // for Element, operator|, text, separatorCharacter, Elements, BorderStyle, Decorator, emptyElement, size, gridbox, EQUAL, flex, flex_shrink, HEIGHT, WIDTH
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool IsCell(int x, int y) {
|
||||||
|
return x % 2 == 1 && y % 2 == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string charset[6][6] = {
|
||||||
|
{"┌", "┐", "└", "┘", "─", "│"}, //
|
||||||
|
{"┏", "┓", "┗", "┛", "━", "┃"}, //
|
||||||
|
{"╔", "╗", "╚", "╝", "═", "║"}, //
|
||||||
|
{"╭", "╮", "╰", "╯", "─", "│"}, //
|
||||||
|
{" ", " ", " ", " ", " ", " "}, //
|
||||||
|
};
|
||||||
|
|
||||||
|
int Wrap(int input, int modulo) {
|
||||||
|
input %= modulo;
|
||||||
|
input += modulo;
|
||||||
|
input %= modulo;
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Order(int& a, int& b) {
|
||||||
|
if (a >= b)
|
||||||
|
std::swap(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Table::Table(std::vector<std::vector<std::string>> input) {
|
||||||
|
input_dim_y_ = input.size();
|
||||||
|
input_dim_x_ = 0;
|
||||||
|
for (auto& row : input)
|
||||||
|
input_dim_x_ = std::max(input_dim_x_, (int)row.size());
|
||||||
|
|
||||||
|
dim_y_ = 2 * input_dim_y_ + 1;
|
||||||
|
dim_x_ = 2 * input_dim_x_ + 1;
|
||||||
|
|
||||||
|
// Reserve space.
|
||||||
|
elements_.resize(dim_y_);
|
||||||
|
for (int y = 0; y < dim_y_; ++y)
|
||||||
|
elements_[y].resize(dim_x_);
|
||||||
|
|
||||||
|
// Transfert elements_ from |input| toward |elements_|.
|
||||||
|
{
|
||||||
|
int y = 1;
|
||||||
|
for (auto& row : input) {
|
||||||
|
int x = 1;
|
||||||
|
for (auto& cell : row) {
|
||||||
|
elements_[y][x] = text(cell);
|
||||||
|
x += 2;
|
||||||
|
}
|
||||||
|
y += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add empty element for the border.
|
||||||
|
for (int y = 0; y < dim_y_; ++y) {
|
||||||
|
for (int x = 0; x < dim_x_; ++x) {
|
||||||
|
auto& element = elements_[y][x];
|
||||||
|
|
||||||
|
if (IsCell(x, y)) {
|
||||||
|
if (!element)
|
||||||
|
element = emptyElement();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = emptyElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSelection Table::SelectRow(int index) {
|
||||||
|
return SelectRectangle(0, -1, index, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSelection Table::SelectRows(int row_min, int row_max) {
|
||||||
|
return SelectRectangle(0, -1, row_min, row_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSelection Table::SelectColumn(int index) {
|
||||||
|
return SelectRectangle(index, index, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSelection Table::SelectColumns(int column_min, int column_max) {
|
||||||
|
return SelectRectangle(column_min, column_max, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSelection Table::SelectCell(int column, int row) {
|
||||||
|
return SelectRectangle(column, column, row, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSelection Table::SelectRectangle(int column_min,
|
||||||
|
int column_max,
|
||||||
|
int row_min,
|
||||||
|
int row_max) {
|
||||||
|
column_min = Wrap(column_min, input_dim_x_);
|
||||||
|
column_max = Wrap(column_max, input_dim_x_);
|
||||||
|
Order(column_min, column_max);
|
||||||
|
row_min = Wrap(row_min, input_dim_y_);
|
||||||
|
row_max = Wrap(row_max, input_dim_y_);
|
||||||
|
Order(row_min, row_max);
|
||||||
|
|
||||||
|
TableSelection output;
|
||||||
|
output.table_ = this;
|
||||||
|
output.x_min_ = 2 * column_min;
|
||||||
|
output.x_max_ = 2 * column_max + 2;
|
||||||
|
output.y_min_ = 2 * row_min;
|
||||||
|
output.y_max_ = 2 * row_max + 2;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSelection Table::SelectAll() {
|
||||||
|
TableSelection output;
|
||||||
|
output.table_ = this;
|
||||||
|
output.x_min_ = 0;
|
||||||
|
output.x_max_ = dim_x_ - 1;
|
||||||
|
output.y_min_ = 0;
|
||||||
|
output.y_max_ = dim_y_ - 1;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
Element Table::Render() {
|
||||||
|
for (int y = 0; y < dim_y_; ++y) {
|
||||||
|
for (int x = 0; x < dim_x_; ++x) {
|
||||||
|
auto& it = elements_[y][x];
|
||||||
|
|
||||||
|
// Line
|
||||||
|
if ((x + y) % 2 == 1) {
|
||||||
|
it = std::move(it) | flex;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cells
|
||||||
|
if ((x % 2) == 1 && (y % 2) == 1) {
|
||||||
|
it = std::move(it) | flex_shrink;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corners
|
||||||
|
it = std::move(it) | size(WIDTH, EQUAL, 0) | size(HEIGHT, EQUAL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gridbox(std::move(elements_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::Decorate(Decorator decorator) {
|
||||||
|
for (int y = y_min_; y <= y_max_; ++y) {
|
||||||
|
for (int x = x_min_; x <= x_max_; ++x) {
|
||||||
|
Element& e = table_->elements_[y][x];
|
||||||
|
e = std::move(e) | decorator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::DecorateCells(Decorator decorator) {
|
||||||
|
for (int y = y_min_; y <= y_max_; ++y) {
|
||||||
|
for (int x = x_min_; x <= x_max_; ++x) {
|
||||||
|
if (y % 2 && x % 2) {
|
||||||
|
Element& e = table_->elements_[y][x];
|
||||||
|
e = std::move(e) | decorator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::DecorateAlternateColumn(Decorator decorator,
|
||||||
|
int modulo,
|
||||||
|
int shift) {
|
||||||
|
for (int y = y_min_; y <= y_max_; ++y) {
|
||||||
|
for (int x = x_min_; x <= x_max_; ++x) {
|
||||||
|
if (y % 2 && (x / 2) % modulo == shift) {
|
||||||
|
Element& e = table_->elements_[y][x];
|
||||||
|
e = std::move(e) | decorator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::DecorateAlternateRow(Decorator decorator,
|
||||||
|
int modulo,
|
||||||
|
int shift) {
|
||||||
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||||
|
for (int x = x_min_; x <= x_max_; ++x) {
|
||||||
|
if (y % 2 && (y / 2) % modulo == shift) {
|
||||||
|
Element& e = table_->elements_[y][x];
|
||||||
|
e = std::move(e) | decorator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::DecorateCellsAlternateColumn(Decorator decorator,
|
||||||
|
int modulo,
|
||||||
|
int shift) {
|
||||||
|
for (int y = y_min_; y <= y_max_; ++y) {
|
||||||
|
for (int x = x_min_; x <= x_max_; ++x) {
|
||||||
|
if (y % 2 && x % 2 && ((x / 2) % modulo == shift)) {
|
||||||
|
Element& e = table_->elements_[y][x];
|
||||||
|
e = std::move(e) | decorator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::DecorateCellsAlternateRow(Decorator decorator,
|
||||||
|
int modulo,
|
||||||
|
int shift) {
|
||||||
|
for (int y = y_min_; y <= y_max_; ++y) {
|
||||||
|
for (int x = x_min_; x <= x_max_; ++x) {
|
||||||
|
if (y % 2 && x % 2 && ((y / 2) % modulo == shift)) {
|
||||||
|
Element& e = table_->elements_[y][x];
|
||||||
|
e = std::move(e) | decorator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::Border(BorderStyle style) {
|
||||||
|
BorderLeft(style);
|
||||||
|
BorderRight(style);
|
||||||
|
BorderTop(style);
|
||||||
|
BorderBottom(style);
|
||||||
|
|
||||||
|
table_->elements_[y_min_][x_min_] = text(charset[style][0]);
|
||||||
|
table_->elements_[y_min_][x_max_] = text(charset[style][1]);
|
||||||
|
table_->elements_[y_max_][x_min_] = text(charset[style][2]);
|
||||||
|
table_->elements_[y_max_][x_max_] = text(charset[style][3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::Separator(BorderStyle style) {
|
||||||
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||||
|
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
||||||
|
if (y % 2 == 0 || x % 2 == 0) {
|
||||||
|
Element& e = table_->elements_[y][x];
|
||||||
|
e = (y % 2) ? separatorCharacter(charset[style][5])
|
||||||
|
: separatorCharacter(charset[style][4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::SeparatorVertical(BorderStyle style) {
|
||||||
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||||
|
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
||||||
|
if (x % 2 == 0) {
|
||||||
|
table_->elements_[y][x] = text(charset[style][5]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::SeparatorHorizontal(BorderStyle style) {
|
||||||
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||||
|
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
||||||
|
if (y % 2 == 0) {
|
||||||
|
table_->elements_[y][x] = text(charset[style][4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::BorderLeft(BorderStyle style) {
|
||||||
|
for (int y = y_min_; y <= y_max_; y++)
|
||||||
|
table_->elements_[y][x_min_] = separatorCharacter(charset[style][5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::BorderRight(BorderStyle style) {
|
||||||
|
for (int y = y_min_; y <= y_max_; y++)
|
||||||
|
table_->elements_[y][x_max_] = separatorCharacter(charset[style][5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::BorderTop(BorderStyle style) {
|
||||||
|
for (int x = x_min_; x <= x_max_; x++)
|
||||||
|
table_->elements_[y_min_][x] = separatorCharacter(charset[style][4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableSelection::BorderBottom(BorderStyle style) {
|
||||||
|
for (int x = x_min_; x <= x_max_; x++)
|
||||||
|
table_->elements_[y_max_][x] = separatorCharacter(charset[style][4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
716
src/ftxui/dom/table_test.cpp
Normal file
716
src/ftxui/dom/table_test.cpp
Normal file
@@ -0,0 +1,716 @@
|
|||||||
|
#include <gtest/gtest-message.h> // for Message
|
||||||
|
#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
|
||||||
|
#include <memory> // for allocator
|
||||||
|
|
||||||
|
#include "ftxui/dom/elements.hpp" // for LIGHT, flex, center, EMPTY, DOUBLE
|
||||||
|
#include "ftxui/dom/node.hpp" // for Render
|
||||||
|
#include "ftxui/dom/table.hpp"
|
||||||
|
#include "ftxui/screen/box.hpp" // for ftxui
|
||||||
|
#include "ftxui/screen/screen.hpp" // for Screen
|
||||||
|
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
|
||||||
|
|
||||||
|
using namespace ftxui;
|
||||||
|
|
||||||
|
TEST(TableTest, Empty) {
|
||||||
|
auto table = Table({});
|
||||||
|
Screen screen(5, 5);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, Basic) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"abcd \r\n"
|
||||||
|
"efgh \r\n"
|
||||||
|
"ijkl \r\n"
|
||||||
|
"mnop \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SeparatorVerticalEmpty) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().SeparatorVertical(EMPTY);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"a b c d \r\n"
|
||||||
|
"e f g h \r\n"
|
||||||
|
"i j k l \r\n"
|
||||||
|
"m n o p \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SeparatorHorizontalEmpty) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().SeparatorHorizontal(EMPTY);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"abcd \r\n"
|
||||||
|
" \r\n"
|
||||||
|
"efgh \r\n"
|
||||||
|
" \r\n"
|
||||||
|
"ijkl \r\n"
|
||||||
|
" \r\n"
|
||||||
|
"mnop \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SeparatorHorizontalLight) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().SeparatorHorizontal(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"abcd \r\n"
|
||||||
|
"──── \r\n"
|
||||||
|
"efgh \r\n"
|
||||||
|
"──── \r\n"
|
||||||
|
"ijkl \r\n"
|
||||||
|
"──── \r\n"
|
||||||
|
"mnop \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SeparatorVerticalLight) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().SeparatorVertical(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"a│b│c│d \r\n"
|
||||||
|
"e│f│g│h \r\n"
|
||||||
|
"i│j│k│l \r\n"
|
||||||
|
"m│n│o│p \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SeparatorLight) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"a│b│c│d \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"e│f│g│h \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"i│j│k│l \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"m│n│o│p \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SeparatorVerticalHorizontalLight) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().SeparatorVertical(LIGHT);
|
||||||
|
table.SelectAll().SeparatorHorizontal(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"a│b│c│d \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"e│f│g│h \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"i│j│k│l \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"m│n│o│p \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SeparatorHorizontalVerticalLight) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().SeparatorHorizontal(LIGHT);
|
||||||
|
table.SelectAll().SeparatorVertical(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"a│b│c│d \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"e│f│g│h \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"i│j│k│l \r\n"
|
||||||
|
"─┼─┼─┼─ \r\n"
|
||||||
|
"m│n│o│p \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, BorderLight) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌────┐ \r\n"
|
||||||
|
"│abcd│ \r\n"
|
||||||
|
"│efgh│ \r\n"
|
||||||
|
"│ijkl│ \r\n"
|
||||||
|
"│mnop│ \r\n"
|
||||||
|
"└────┘ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, BorderSeparatorLight) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌─┬─┬─┬─┐ \r\n"
|
||||||
|
"│a│b│c│d│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│e│f│g│h│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│i│j│k│l│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│m│n│o│p│ \r\n"
|
||||||
|
"└─┴─┴─┴─┘ \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectRow) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectRow(1).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" abcd \r\n"
|
||||||
|
"┌────┐ \r\n"
|
||||||
|
"│efgh│ \r\n"
|
||||||
|
"└────┘ \r\n"
|
||||||
|
" ijkl \r\n"
|
||||||
|
" mnop \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectRowNegative) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectRow(-2).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" abcd \r\n"
|
||||||
|
" efgh \r\n"
|
||||||
|
"┌────┐ \r\n"
|
||||||
|
"│ijkl│ \r\n"
|
||||||
|
"└────┘ \r\n"
|
||||||
|
" mnop \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectColumn) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectColumn(1).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" ┌─┐ \r\n"
|
||||||
|
"a│b│cd \r\n"
|
||||||
|
"e│f│gh \r\n"
|
||||||
|
"i│j│kl \r\n"
|
||||||
|
"m│n│op \r\n"
|
||||||
|
" └─┘ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectColumnNegative) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectColumn(-2).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" ┌─┐ \r\n"
|
||||||
|
"ab│c│d \r\n"
|
||||||
|
"ef│g│h \r\n"
|
||||||
|
"ij│k│l \r\n"
|
||||||
|
"mn│o│p \r\n"
|
||||||
|
" └─┘ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, CrossingBorders) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectRow(1).Border(LIGHT);
|
||||||
|
table.SelectColumn(1).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" ┌─┐ \r\n"
|
||||||
|
" a│b│cd \r\n"
|
||||||
|
"┌─┼─┼──┐ \r\n"
|
||||||
|
"│e│f│gh│ \r\n"
|
||||||
|
"└─┼─┼──┘ \r\n"
|
||||||
|
" i│j│kl \r\n"
|
||||||
|
" m│n│op \r\n"
|
||||||
|
" └─┘ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, CrossingBordersLightAndDouble) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectRow(1).Border(LIGHT);
|
||||||
|
table.SelectColumn(1).Border(DOUBLE);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" ╔═╗ \r\n"
|
||||||
|
" a║b║cd \r\n"
|
||||||
|
"┌─╫─╫──┐ \r\n"
|
||||||
|
"│e║f║gh│ \r\n"
|
||||||
|
"└─╫─╫──┘ \r\n"
|
||||||
|
" i║j║kl \r\n"
|
||||||
|
" m║n║op \r\n"
|
||||||
|
" ╚═╝ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectColumns) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectColumns(1, 2).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" ┌──┐ \r\n"
|
||||||
|
"a│bc│d \r\n"
|
||||||
|
"e│fg│h \r\n"
|
||||||
|
"i│jk│l \r\n"
|
||||||
|
"m│no│p \r\n"
|
||||||
|
" └──┘ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectRows) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectRows(1, 2).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" abcd \r\n"
|
||||||
|
"┌────┐ \r\n"
|
||||||
|
"│efgh│ \r\n"
|
||||||
|
"│ijkl│ \r\n"
|
||||||
|
"└────┘ \r\n"
|
||||||
|
" mnop \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectRectangle) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectRectangle(1, 2, 1, 2).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"a bc d \r\n"
|
||||||
|
" ┌──┐ \r\n"
|
||||||
|
"e│fg│h \r\n"
|
||||||
|
"i│jk│l \r\n"
|
||||||
|
" └──┘ \r\n"
|
||||||
|
"m no p \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectColumnsNegative) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectColumns(1, -1).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" ┌───┐ \r\n"
|
||||||
|
"a│bcd│ \r\n"
|
||||||
|
"e│fgh│ \r\n"
|
||||||
|
"i│jkl│ \r\n"
|
||||||
|
"m│nop│ \r\n"
|
||||||
|
" └───┘ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, SelectInverted) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectColumns(-1, 1).Border(LIGHT);
|
||||||
|
Screen screen(10, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
" ┌───┐ \r\n"
|
||||||
|
"a│bcd│ \r\n"
|
||||||
|
"e│fgh│ \r\n"
|
||||||
|
"i│jkl│ \r\n"
|
||||||
|
"m│nop│ \r\n"
|
||||||
|
" └───┘ \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, ColumnFlex) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
table.SelectColumn(1).Decorate(flex);
|
||||||
|
Screen screen(20, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌─┬────────────┬─┬─┐\r\n"
|
||||||
|
"│a│b │c│d│\r\n"
|
||||||
|
"├─┼────────────┼─┼─┤\r\n"
|
||||||
|
"│e│f │g│h│\r\n"
|
||||||
|
"├─┼────────────┼─┼─┤\r\n"
|
||||||
|
"│i│j │k│l│\r\n"
|
||||||
|
"├─┼────────────┼─┼─┤\r\n"
|
||||||
|
"│m│n │o│p│\r\n"
|
||||||
|
"└─┴────────────┴─┴─┘\r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, ColumnFlexCenter) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
table.SelectColumn(1).Decorate(flex);
|
||||||
|
table.SelectColumn(1).DecorateCells(center);
|
||||||
|
Screen screen(20, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌─┬─┬─┬─┐ \r\n"
|
||||||
|
"│a│b│c│d│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│e│f│g│h│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│i│j│k│l│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│m│n│o│p│ \r\n"
|
||||||
|
"└─┴─┴─┴─┘ \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, ColumnCenter) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
table.SelectColumn(1).DecorateCells(center);
|
||||||
|
Screen screen(20, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌─┬─┬─┬─┐ \r\n"
|
||||||
|
"│a│b│c│d│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│e│f│g│h│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│i│j│k│l│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│m│n│o│p│ \r\n"
|
||||||
|
"└─┴─┴─┴─┘ \r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, ColumnFlexTwo) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
table.SelectColumn(1).Decorate(flex);
|
||||||
|
table.SelectColumn(3).Decorate(flex);
|
||||||
|
Screen screen(20, 10);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌─┬──────┬─┬───────┐\r\n"
|
||||||
|
"│a│b │c│d │\r\n"
|
||||||
|
"├─┼──────┼─┼───────┤\r\n"
|
||||||
|
"│e│f │g│h │\r\n"
|
||||||
|
"├─┼──────┼─┼───────┤\r\n"
|
||||||
|
"│i│j │k│l │\r\n"
|
||||||
|
"├─┼──────┼─┼───────┤\r\n"
|
||||||
|
"│m│n │o│p │\r\n"
|
||||||
|
"└─┴──────┴─┴───────┘\r\n"
|
||||||
|
" ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, RowFlex) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
table.SelectRow(1).Decorate(flex);
|
||||||
|
Screen screen(10, 20);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌─┬─┬─┬─┐ \r\n"
|
||||||
|
"│a│b│c│d│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│e│f│g│h│ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│i│j│k│l│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│m│n│o│p│ \r\n"
|
||||||
|
"└─┴─┴─┴─┘ ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TableTest, RowFlexTwo) {
|
||||||
|
auto table = Table({
|
||||||
|
{"a", "b", "c", "d"},
|
||||||
|
{"e", "f", "g", "h"},
|
||||||
|
{"i", "j", "k", "l"},
|
||||||
|
{"m", "n", "o", "p"},
|
||||||
|
});
|
||||||
|
table.SelectAll().Border(LIGHT);
|
||||||
|
table.SelectAll().Separator(LIGHT);
|
||||||
|
table.SelectRow(1).Decorate(flex);
|
||||||
|
table.SelectRow(3).Decorate(flex);
|
||||||
|
Screen screen(10, 20);
|
||||||
|
Render(screen, table.Render());
|
||||||
|
EXPECT_EQ(
|
||||||
|
"┌─┬─┬─┬─┐ \r\n"
|
||||||
|
"│a│b│c│d│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│e│f│g│h│ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│i│j│k│l│ \r\n"
|
||||||
|
"├─┼─┼─┼─┤ \r\n"
|
||||||
|
"│m│n│o│p│ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"│ │ │ │ │ \r\n"
|
||||||
|
"└─┴─┴─┴─┘ ",
|
||||||
|
screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
// the LICENSE file.
|
@@ -75,6 +75,18 @@ Dimensions Dimension::Fit(Element& e) {
|
|||||||
std::min(e->requirement().min_y, size.dimy)};
|
std::min(e->requirement().min_y, size.dimy)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An element of size 0x0 drawing nothing.
|
||||||
|
/// @ingroup dom
|
||||||
|
Element emptyElement() {
|
||||||
|
class Impl : public Node {
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
requirement_.min_x = 0;
|
||||||
|
requirement_.min_x = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return std::make_unique<Impl>();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
|
||||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
#include <stdint.h> // for uint16_t
|
|
||||||
#include <iostream> // for operator<<, stringstream, basic_ostream, flush, cout, ostream
|
#include <iostream> // for operator<<, stringstream, basic_ostream, flush, cout, ostream
|
||||||
#include <map> // for _Rb_tree_const_iterator, map, operator!=, operator==
|
#include <map> // for _Rb_tree_const_iterator, map, operator!=, operator==
|
||||||
#include <memory> // for allocator, allocator_traits<>::value_type
|
#include <memory> // for allocator, allocator_traits<>::value_type
|
||||||
@@ -98,16 +97,21 @@ struct TileEncoding {
|
|||||||
unsigned int down : 2;
|
unsigned int down : 2;
|
||||||
unsigned int round : 1;
|
unsigned int round : 1;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
bool operator<(const TileEncoding& other) const {
|
bool operator<(const TileEncoding& other) const {
|
||||||
union Converter {
|
if (left < other.left) return true;
|
||||||
TileEncoding input;
|
if (left > other.left) return false;
|
||||||
uint16_t output = 0;
|
if (top < other.top) return true;
|
||||||
};
|
if (top > other.top) return false;
|
||||||
Converter a, b;
|
if (right < other.right) return true;
|
||||||
a.input = *this;
|
if (right > other.right) return false;
|
||||||
b.input = other;
|
if (down < other.down) return true;
|
||||||
return a.output < b.output;
|
if (down > other.down) return false;
|
||||||
|
if (round < other.round) return true;
|
||||||
|
if (round > other.round) return false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@@ -18,9 +18,18 @@
|
|||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
static Dimensions fallback_size{140, 43};
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
// The Microsoft default "cmd" returns errors above.
|
||||||
|
static Dimensions fallback_size{80, 80};
|
||||||
|
#else
|
||||||
|
static Dimensions fallback_size{80, 25};
|
||||||
|
#endif
|
||||||
|
|
||||||
Dimensions Terminal::Size() {
|
Dimensions Terminal::Size() {
|
||||||
#if defined(__EMSCRIPTEN__)
|
#if defined(__EMSCRIPTEN__)
|
||||||
return Dimensions{140, 43};
|
return fallback_size;
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
|
||||||
@@ -29,16 +38,24 @@ Dimensions Terminal::Size() {
|
|||||||
csbi.srWindow.Bottom - csbi.srWindow.Top + 1};
|
csbi.srWindow.Bottom - csbi.srWindow.Top + 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Microsoft default "cmd" returns errors above.
|
return fallback_size;
|
||||||
return Dimensions{80, 80};
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
winsize w;
|
winsize w{};
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
if (w.ws_col == 0 || w.ws_row == 0) {
|
||||||
|
return fallback_size;
|
||||||
|
}
|
||||||
return Dimensions{w.ws_col, w.ws_row};
|
return Dimensions{w.ws_col, w.ws_row};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Override terminal size in case auto-detection fails
|
||||||
|
/// @param fallbackSize Terminal dimensions to fallback to
|
||||||
|
void Terminal::SetFallbackSize(const Dimensions& fallbackSize) {
|
||||||
|
fallback_size = fallbackSize;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* Safe(const char* c) {
|
const char* Safe(const char* c) {
|
||||||
|
Reference in New Issue
Block a user