diff --git a/doc/mainpage.md b/doc/mainpage.md
index 94fe5d8..38434b9 100644
--- a/doc/mainpage.md
+++ b/doc/mainpage.md
@@ -44,28 +44,71 @@ int main(void) {
└────┘└─────────────────────────────────────────────────────────────────┘└─────┘
```
-**cmake**
-```c
+# Build
+
+## Using CMake
+
+CMakeLists.txt
+~~~cmake
cmake_minimum_required (VERSION 3.11)
+# --- Fetch FTXUI --------------------------------------------------------------
include(FetchContent)
+
+set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE)
FetchContent_Declare(ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
+ # Specify a GIT_TAG here.
)
+
FetchContent_GetProperties(ftxui)
if(NOT ftxui_POPULATED)
FetchContent_Populate(ftxui)
add_subdirectory(${ftxui_SOURCE_DIR} ${ftxui_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
-add_executable(main src/main.cpp)
-target_link_libraries(main
+# ------------------------------------------------------------------------------
+
+project(ftxui-starter
+ LANGUAGES CXX
+ VERSION 1.0.0
+)
+
+add_executable(ftxui-starter src/main.cpp)
+target_include_directories(ftxui-starter PRIVATE src)
+
+target_link_libraries(ftxui-starter
PRIVATE ftxui::screen
PRIVATE ftxui::dom
PRIVATE ftxui::component # Not needed for this example.
)
-set_target_properties(main PROPERTIES CXX_STANDARD 17)
-```
+
+# C++17 is used. We requires fold expressions at least.
+set_target_properties(ftxui-starter PROPERTIES CXX_STANDARD 17)
+
+~~~
+
+Build
+~~~
+mkdir build && cd build
+cmake ..
+make
+./main
+~~~
+
+## Using NXXM
+
+**.nxxm/deps**
+~~~json
+{
+ "ArthurSonzogni/FTXUI": {}
+}
+~~~
+
+Build:
+~~~
+nxxm . -t clang-cxx17
+~~~
# List of modules.
@@ -82,7 +125,7 @@ input. It defines a set of ftxui::Component. The use can navigates using the
arrow keys and interact with widgets like checkbox/inputbox/... You can make you
own components.
-## screen
+# screen
It defines a ftxui::Screen. This is a grid of ftxui::Pixel. A Pixel represent a
unicode character and its associated style (bold, colors, etc...).
@@ -106,7 +149,7 @@ The screen can be printed as a string using ftxui::Screen::ToString().
}
~~~
-## dom
+# dom
This module defines a hierachical set of Element. An element manages layout and can be responsive to the terminal dimensions.
@@ -130,30 +173,6 @@ You only need one header: ftxui/dom/elements.hpp
\include ftxui/dom/elements.hpp
-## component
-
-Finally, the ftxui/component directory defines the logic to get interactivity.
-
-Please take a look at ./examples/component
-
-This provides:
-1. A main loop.
-2. Get events and respond to them.
-3. A predefined implementation of "keyboard navigation".
-4. A set of predefined widget: CheckBox, RadioBox, Input, Menu, Toggle.
-
-
-**List of Component**
-
-You only need one header: ftxui/dom/component.hpp
-
-\include ftxui/component/component.hpp
-
-# ftxui/dom
-
-Every elements of the dom are declared from:
-\ref ftxui/dom/elements.hpp
-
## text
The most simple widget. It displays a text.
@@ -226,6 +245,7 @@ border(gauge(0.5))
~~~
## graph
+
@htmlonly
@endhtmlonly
@@ -369,7 +389,25 @@ An horizontal flow layout is implemented by:
└────┘└───────────────────────────────────┘└───────────────────────────────────┘
~~~
-# ftxui/component
+
+# component
+
+The `ftxui/component` directory defines the logic to get produce
+interactive component responding to user's events (keyboard, mouse, etc...)
+
+A ftxui::ScreenInteractive defines a main loop to render a component.
+
+A ftxui::Component is a shared pointer to a ftxui::ComponentBase. The later
+defines
+ - ftxui::ComponentBase::Render(): How to render the interface.
+ - ftxui::ComponentBase::OnEvent(): How to react to events.
+ - ftxui::ComponentBase::Add(): Give a parent/child relation ship in between
+ two component. This defines a tree a components, which help properly define
+ how keyboard navigation works.
+
+Predefined components are available in `ftxui/dom/component.hpp`:
+
+\include ftxui/component/component.hpp
Element are stateless object. On the other side, components are used when an
internal state is needed. Components are used to interact with the user with
@@ -377,7 +415,7 @@ its keyboard. They handle keyboard navigation, including component focus.
## Input
-The component: \ref ftxui::Input
+Produced by: ftxui::Input() from "ftxui/component/component.hpp"
@htmlonly
@@ -385,7 +423,7 @@ The component: \ref ftxui::Input
## Menu
-The component: \ref ftxui::Menu
+Produced by: ftxui::Menu() from "ftxui/component/component.hpp"
@htmlonly
@@ -393,7 +431,7 @@ The component: \ref ftxui::Menu
## Toggle.
-The component: \ref ftxui::Toggle
+Produced by: ftxui::Toggle() from "ftxui/component/component.hpp"
@htmlonly
@@ -401,7 +439,7 @@ The component: \ref ftxui::Toggle
## CheckBox
-The component: \ref ftxui::CheckBox
+Produced by: ftxui::Checkbox() from "ftxui/component/component.hpp"
@htmlonly
@@ -409,99 +447,32 @@ The component: \ref ftxui::CheckBox
## RadioBox
-The component: \ref ftxui::RadioBox
+Produced by: ftxui::Radiobox() from "ftxui/component/component.hpp"
@htmlonly
@endhtmlonly
-# Build
+## Renderer
-Assuming this example example.cpp file.
+Produced by: ftxui::Renderer() from \ref "ftxui/component/component.hpp". This
+component decorate another one by using a different function to render an
+interface.
-**main.cpp**
-~~~cpp
-#include "ftxui/screen/screen.c
-#include "ftxui/dom/elements.c
-#include
+## Container::Horizontal
-int main(int argc, const char *argv[]) {
- using namespace ftxui;
- auto document =
- hbox({
- text(L"left") | bold | border,
- text(L"middle") | flex | border,
- text(L"right") | border,
- });
- auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
- Render(screen, document);
+Produced by: ftxui::Container::Horizontal() from
+"ftxui/component/component.hpp". It displays a list of components horizontally
+and handle keyboard/mouse navigation.
- std::cout << screen.ToString();
+## Container::Vertial
- return 0;
-}
-~~~
+Produced by: ftxui::Container::Vertical() from
+"ftxui/component/component.hpp". It displays a list of components vertically
+and handles keyboard/mouse navigation.
-## Using CMake
+## Container::Tab
-CMakeLists.txt
-~~~cmake
-cmake_minimum_required (VERSION 3.11)
-
-# --- Fetch FTXUI --------------------------------------------------------------
-include(FetchContent)
-
-set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE)
-FetchContent_Declare(ftxui
- GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
- # Specify a GIT TAG here.
-)
-
-FetchContent_GetProperties(ftxui)
-if(NOT ftxui_POPULATED)
- FetchContent_Populate(ftxui)
- add_subdirectory(${ftxui_SOURCE_DIR} ${ftxui_BINARY_DIR} EXCLUDE_FROM_ALL)
-endif()
-
-# ------------------------------------------------------------------------------
-
-project(ftxui-starter
- LANGUAGES CXX
- VERSION 1.0.0
-)
-
-add_executable(ftxui-starter src/main.cpp)
-target_include_directories(ftxui-starter PRIVATE src)
-
-target_link_libraries(ftxui-starter
- PRIVATE ftxui::screen
- PRIVATE ftxui::dom
- PRIVATE ftxui::component # Not needed for this example.
-)
-
-# C++17 is used. We requires fold expressions at least.
-set_target_properties(ftxui-starter PROPERTIES CXX_STANDARD 17)
-
-~~~
-
-Build
-~~~
-mkdir build && cd build
-cmake ..
-make
-./main
-~~~
-
-## Using NXXM
-
-**.nxxm/deps**
-~~~json
-{
- "ArthurSonzogni/FTXUI": {}
-}
-~~~
-
-Build:
-~~~
-nxxm . -t clang-cxx17
-~~~
+Produced by: ftxui::Container::Tab() from
+"ftxui/component/component.hpp". It take a list of component and display only
+one of them. This is useful for implementing a tab bar.
diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp
index b32459d..47e942c 100644
--- a/include/ftxui/component/component.hpp
+++ b/include/ftxui/component/component.hpp
@@ -32,11 +32,11 @@ Component Renderer(std::function);
template // T = {int, float}
Component Slider(std::wstring label, T* value, T min, T max, T increment);
-// namespace Component {
-// Component Vertical(Components children);
-// Component Horizontal(Components children);
-// Component Tab(int* selector, Components children);
-//} // namespace Component
+namespace Container {
+Component Vertical(Components children);
+Component Horizontal(Components children);
+Component Tab(int* selector, Components children);
+} // namespace Container
}; // namespace ftxui
diff --git a/include/ftxui/component/container.hpp b/include/ftxui/component/container.hpp
index 19277c7..f15b65f 100644
--- a/include/ftxui/component/container.hpp
+++ b/include/ftxui/component/container.hpp
@@ -9,7 +9,7 @@
namespace ftxui {
/// @brief A component where focus and events are automatically handled for you.
-class Container : public ComponentBase {
+class ContainerBase : public ComponentBase {
public:
static Component Vertical();
static Component Vertical(Components children);
@@ -20,7 +20,7 @@ class Container : public ComponentBase {
static Component Tab(int* selector);
static Component Tab(int* selector, Components children);
- ~Container() override = default;
+ ~ContainerBase() override = default;
// Component override.
bool OnEvent(Event event) override;
@@ -30,13 +30,13 @@ class Container : public ComponentBase {
protected:
// Handlers
- using EventHandler = bool (Container::*)(Event);
+ using EventHandler = bool (ContainerBase::*)(Event);
bool VerticalEvent(Event event);
bool HorizontalEvent(Event event);
bool TabEvent(Event) { return false; }
EventHandler event_handler_;
- using RenderHandler = Element (Container::*)();
+ using RenderHandler = Element (ContainerBase::*)();
Element VerticalRender();
Element HorizontalRender();
Element TabRender();
diff --git a/src/ftxui/component/container.cpp b/src/ftxui/component/container.cpp
index 7efc0dc..3dc9fdf 100644
--- a/src/ftxui/component/container.cpp
+++ b/src/ftxui/component/container.cpp
@@ -9,65 +9,120 @@
namespace ftxui {
-Component ContainerVertical(Components children) {
- return Container::Vertical(std::move(children));
+namespace Container {
+
+/// @brief A list of components, drawn one by one vertically and navigated
+/// vertically using up/down arrow key or 'j'/'k' keys.
+/// @param children the list of components.
+/// @ingroup component
+/// @see ContainerBase
+///
+/// ### Example
+///
+/// ```cpp
+/// auto container = Container::Vertical({
+/// children_1,
+/// children_2,
+/// children_3,
+/// children_4,
+/// });
+/// ```
+Component Vertical(Components children) {
+ return ContainerBase::Vertical(std::move(children));
}
-Component ContainerHorizontal(Components children) {
- return Container::Horizontal(std::move(children));
+/// @brief A list of components, drawn one by one horizontally and navigated
+/// horizontally using left/right arrow key or 'h'/'l' keys.
+/// @param children the list of components.
+/// @ingroup component
+/// @see ContainerBase
+///
+/// ### Example
+///
+/// ```cpp
+/// auto container = Container::Horizontal({
+/// children_1,
+/// children_2,
+/// children_3,
+/// children_4,
+/// });
+/// ```
+Component Horizontal(Components children) {
+ return ContainerBase::Horizontal(std::move(children));
}
-Component ContainerTab(int* selector, Components children) {
- return Container::Tab(selector, std::move(children));
+/// @brief A list of components, where only one is drawn and interacted with at
+/// a time. The |selector| gives the index of the selected component. This is
+/// useful to implement tabs.
+/// @param selector The index of the drawn children.
+/// @param children the list of components.
+/// @ingroup component
+/// @see ContainerBase
+///
+/// ### Example
+///
+/// ```cpp
+/// int tab_drawn = 0;
+/// auto container = Container::Tab(&tab_drawn, {
+/// children_1,
+/// children_2,
+/// children_3,
+/// children_4,
+/// });
+/// ```
+Component Tab(int* selector, Components children) {
+ return ContainerBase::Tab(selector, std::move(children));
}
+} // namespace Container
+
// static
-Component Container::Vertical() {
+Component ContainerBase::Vertical() {
return Vertical({});
}
// static
-Component Container::Vertical(Components children) {
+Component ContainerBase::Vertical(Components children) {
auto container = std::make_shared();
- container->event_handler_ = &Container::VerticalEvent;
- container->render_handler_ = &Container::VerticalRender;
+ container->event_handler_ = &ContainerBase::VerticalEvent;
+ container->render_handler_ = &ContainerBase::VerticalRender;
for (Component& child : children)
container->Add(std::move(child));
return container;
}
// static
-Component Container::Horizontal() {
+Component ContainerBase::Horizontal() {
return Horizontal({});
}
// static
-Component Container::Horizontal(Components children) {
+Component ContainerBase::Horizontal(Components children) {
auto container = std::make_shared();
- container->event_handler_ = &Container::HorizontalEvent;
- container->render_handler_ = &Container::HorizontalRender;
+ container->event_handler_ = &ContainerBase::HorizontalEvent;
+ container->render_handler_ = &ContainerBase::HorizontalRender;
for (Component& child : children)
container->Add(std::move(child));
return container;
}
// static
-Component Container::Tab(int* selector) {
+Component ContainerBase::Tab(int* selector) {
return Tab(selector, {});
}
// static
-Component Container::Tab(int* selector, Components children) {
+Component ContainerBase::Tab(int* selector, Components children) {
auto container = std::make_shared();
container->selector_ = selector;
- container->event_handler_ = &Container::TabEvent;
- container->render_handler_ = &Container::TabRender;
+ container->event_handler_ = &ContainerBase::TabEvent;
+ container->render_handler_ = &ContainerBase::TabRender;
for (Component& child : children)
container->Add(std::move(child));
return container;
}
-bool Container::OnEvent(Event event) {
+bool ContainerBase::OnEvent(Event event) {
if (event.is_mouse())
return OnMouseEvent(event);
@@ -80,7 +135,7 @@ bool Container::OnEvent(Event event) {
return (this->*event_handler_)(event);
}
-Component Container::ActiveChild() {
+Component ContainerBase::ActiveChild() {
if (children_.size() == 0)
return nullptr;
@@ -88,7 +143,7 @@ Component Container::ActiveChild() {
return children_[selected % children_.size()];
}
-void Container::SetActiveChild(ComponentBase* child) {
+void ContainerBase::SetActiveChild(ComponentBase* child) {
for (size_t i = 0; i < children_.size(); ++i) {
if (children_[i].get() == child) {
(selector_ ? *selector_ : selected_) = i;
@@ -97,7 +152,7 @@ void Container::SetActiveChild(ComponentBase* child) {
}
}
-bool Container::VerticalEvent(Event event) {
+bool ContainerBase::VerticalEvent(Event event) {
int old_selected = selected_;
if (event == Event::ArrowUp || event == Event::Character('k'))
selected_--;
@@ -112,7 +167,7 @@ bool Container::VerticalEvent(Event event) {
return old_selected != selected_;
}
-bool Container::HorizontalEvent(Event event) {
+bool ContainerBase::HorizontalEvent(Event event) {
int old_selected = selected_;
if (event == Event::ArrowLeft || event == Event::Character('h'))
selected_--;
@@ -127,11 +182,11 @@ bool Container::HorizontalEvent(Event event) {
return old_selected != selected_;
}
-Element Container::Render() {
+Element ContainerBase::Render() {
return (this->*render_handler_)();
}
-Element Container::VerticalRender() {
+Element ContainerBase::VerticalRender() {
Elements elements;
for (auto& it : children_)
elements.push_back(it->Render());
@@ -140,7 +195,7 @@ Element Container::VerticalRender() {
return vbox(std::move(elements));
}
-Element Container::HorizontalRender() {
+Element ContainerBase::HorizontalRender() {
Elements elements;
for (auto& it : children_)
elements.push_back(it->Render());
@@ -149,14 +204,14 @@ Element Container::HorizontalRender() {
return hbox(std::move(elements));
}
-Element Container::TabRender() {
+Element ContainerBase::TabRender() {
Component active_child = ActiveChild();
if (active_child)
return active_child->Render();
return text(L"Empty container");
}
-bool Container::OnMouseEvent(Event event) {
+bool ContainerBase::OnMouseEvent(Event event) {
if (selector_)
return ActiveChild()->OnEvent(event);
diff --git a/src/ftxui/component/renderer.cpp b/src/ftxui/component/renderer.cpp
index 27a0c9e..95fdd9a 100644
--- a/src/ftxui/component/renderer.cpp
+++ b/src/ftxui/component/renderer.cpp
@@ -27,10 +27,43 @@ class RendererBase : public ComponentBase {
std::function render_;
};
+/// @brief Return a component, using |render| to render its interface.
+/// @param render The function drawing the interface.
+/// @ingroup component
+///
+/// ### Example
+///
+/// ```cpp
+/// auto screen = ScreenInteractive::TerminalOutput();
+/// auto renderer = Renderer([] {
+/// return text(L"My interface");
+/// });
+/// screen.Loop(renderer);
+/// ```
Component Renderer(std::function render) {
return Make(std::move(render));
}
+/// @brief Return a new Component, similar to |child|, but using |render| as the
+/// Component::Render() event.
+/// @param child The component to forward events to.
+/// @param render The function drawing the interface.
+/// @ingroup component
+///
+/// ### Example
+///
+/// ```cpp
+/// auto screen = ScreenInteractive::TerminalOutput();
+/// std::wstring label = "Click to quit";
+/// auto button = Button(&label, screen.ExitLoopClosure());
+/// auto renderer = Renderer(button, [&] {
+/// return hbox({
+/// text("A button:"),
+/// button->Render(),
+/// });
+/// });
+/// screen.Loop(renderer);
+/// ```
Component Renderer(Component child, std::function render) {
Component renderer = Renderer(std::move(render));
renderer->Add(std::move(child));