mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-26 12:37:06 +08:00
Implement a lot of new features.
This commit deserve to be cut into at least 8 sub commit. Sorry, I acknowledge this is bad... Here are the new features: * dom decorator: bold, dim, underlined, inverted. * component mechanism * components * menu * toogle
This commit is contained in:
parent
dd92b89611
commit
711b71688e
@ -1,4 +1,8 @@
|
|||||||
add_subdirectory(frame)
|
add_subdirectory(frame)
|
||||||
add_subdirectory(gauge)
|
add_subdirectory(gauge)
|
||||||
|
add_subdirectory(menu)
|
||||||
|
add_subdirectory(menu2)
|
||||||
|
add_subdirectory(print_key_press)
|
||||||
add_subdirectory(separator)
|
add_subdirectory(separator)
|
||||||
add_subdirectory(vbox_hbox)
|
add_subdirectory(vbox_hbox)
|
||||||
|
add_subdirectory(toggle)
|
||||||
|
@ -2,15 +2,15 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
using namespace ftxui::dom;
|
using namespace ftxui::dom;
|
||||||
auto document =
|
auto document =
|
||||||
hbox(
|
hbox(
|
||||||
frame(
|
frame(hcenter(text(L" main frame ")),
|
||||||
vbox(
|
vbox(
|
||||||
text(L"Line 1"),
|
text(L"Line 1"),
|
||||||
text(L"Line 2"),
|
text(L"Line 2"),
|
||||||
@ -22,10 +22,24 @@ int main(int argc, const char *argv[])
|
|||||||
text(L"Line 6")
|
text(L"Line 6")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
hbox(
|
||||||
|
frame(text(L"frame 2"),
|
||||||
|
vbox(
|
||||||
|
text(L"Line 4"),
|
||||||
|
text(L"Line 5"),
|
||||||
|
text(L"Line 6")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
frame(text(L"frame 3"),
|
||||||
|
vbox(
|
||||||
text(L"Line 7"),
|
text(L"Line 7"),
|
||||||
text(L"Line 8"),
|
text(L"Line 8"),
|
||||||
text(L"Line 9")
|
text(L"Line 9")
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
text(L"footer footer footer footer footer")
|
||||||
|
)
|
||||||
),
|
),
|
||||||
flex()
|
flex()
|
||||||
);
|
);
|
||||||
|
@ -2,15 +2,21 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
for(float percentage = 0; percentage <= 1.0; percentage+=0.001) {
|
for(float percentage = 0; percentage <= 1.0; percentage+=0.001) {
|
||||||
|
std::wstring data_downloaded =
|
||||||
|
std::to_wstring(int(percentage * 44100)) + L"/44100";
|
||||||
using namespace ftxui::dom;
|
using namespace ftxui::dom;
|
||||||
auto document =
|
auto document =
|
||||||
hbox(text(L"gauge = -"), flex(gauge(percentage)), text(L"-"));
|
hbox(
|
||||||
|
text(L"downloading:"),
|
||||||
|
flex(gauge(percentage)),
|
||||||
|
text(L" " + data_downloaded)
|
||||||
|
);
|
||||||
auto screen = ftxui::Screen(100, 1);
|
auto screen = ftxui::Screen(100, 1);
|
||||||
Render(screen, document.get());
|
Render(screen, document.get());
|
||||||
std::cout << '\r' << screen.ToString() << std::flush;
|
std::cout << '\r' << screen.ToString() << std::flush;
|
||||||
|
4
examples/menu/CMakeLists.txt
Normal file
4
examples/menu/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
add_executable(menu_main
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(menu_main PRIVATE ftxui)
|
21
examples/menu/main.cpp
Normal file
21
examples/menu/main.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "ftxui/screen_interactive.hpp"
|
||||||
|
#include "ftxui/component/menu.hpp"
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
ftxui::ScreenInteractive screen(30,3);
|
||||||
|
ftxui::component::Menu menu(screen.delegate());
|
||||||
|
menu.entries = {
|
||||||
|
L"entry 1",
|
||||||
|
L"entry 2",
|
||||||
|
L"entry 3"
|
||||||
|
};
|
||||||
|
menu.selected = 0;
|
||||||
|
menu.on_enter = screen.ExitLoopClosure();
|
||||||
|
|
||||||
|
screen.Loop();
|
||||||
|
}
|
4
examples/menu2/CMakeLists.txt
Normal file
4
examples/menu2/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
add_executable(menu2_main
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(menu2_main PRIVATE ftxui)
|
75
examples/menu2/main.cpp
Normal file
75
examples/menu2/main.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "ftxui/screen_interactive.hpp"
|
||||||
|
#include "ftxui/component/menu.hpp"
|
||||||
|
#include "ftxui/component/component_horizontal.hpp"
|
||||||
|
#include "ftxui/component/component_vertical.hpp"
|
||||||
|
#include "ftxui/util/string.hpp"
|
||||||
|
|
||||||
|
using namespace ftxui::component;
|
||||||
|
using namespace ftxui::dom;
|
||||||
|
|
||||||
|
class MyComponent : ComponentHorizontal {
|
||||||
|
public:
|
||||||
|
MyComponent(ftxui::component::Delegate* delegate)
|
||||||
|
: ComponentHorizontal(delegate),
|
||||||
|
left_menu(delegate->NewChild()),
|
||||||
|
right_menu(delegate->NewChild()) {
|
||||||
|
left_menu.entries = {L"0%", L"10%", L"20%", L"30%", L"40%", L"50%",
|
||||||
|
L"60%", L"70%", L"80%", L"90%"};
|
||||||
|
right_menu.entries = {L"0%", L"1%", L"2%", L"3%", L"4%", L"5%",
|
||||||
|
L"6%", L"7%", L"8%", L"9%", L"10%"};
|
||||||
|
|
||||||
|
left_menu.on_enter = [this]() { on_enter(); };
|
||||||
|
right_menu.on_enter = [this]() { on_enter(); };
|
||||||
|
Focus(&left_menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<void()> on_enter = [](){};
|
||||||
|
private:
|
||||||
|
Menu left_menu;
|
||||||
|
Menu right_menu;
|
||||||
|
|
||||||
|
Element Render() override {
|
||||||
|
int sum = left_menu.selected * 10 + right_menu.selected;
|
||||||
|
return
|
||||||
|
frame(
|
||||||
|
vbox(
|
||||||
|
// -------- Top panel --------------
|
||||||
|
hbox(
|
||||||
|
// -------- Left Menu --------------
|
||||||
|
flex(
|
||||||
|
vbox(
|
||||||
|
hcenter(bold(text(L"Percentage by 10%"))),
|
||||||
|
left_menu.Render()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// -------- Right Menu --------------
|
||||||
|
flex(
|
||||||
|
vbox(
|
||||||
|
hcenter(bold(text(L"Percentage by 1%"))),
|
||||||
|
right_menu.Render()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
flex()
|
||||||
|
),
|
||||||
|
separator(),
|
||||||
|
// -------- Bottom panel --------------
|
||||||
|
flex(vbox(
|
||||||
|
hbox(text(L" gauge : "), gauge(sum/100.0)),
|
||||||
|
hbox(text(L" text : "), text(to_wstring(std::to_string(sum) + " %")))
|
||||||
|
))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
ftxui::ScreenInteractive screen(60,17);
|
||||||
|
MyComponent component(screen.delegate());
|
||||||
|
component.on_enter = screen.ExitLoopClosure();
|
||||||
|
screen.Loop();
|
||||||
|
}
|
4
examples/print_key_press/CMakeLists.txt
Normal file
4
examples/print_key_press/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
add_executable(print_key_press
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(print_key_press PRIVATE ftxui)
|
44
examples/print_key_press/main.cpp
Normal file
44
examples/print_key_press/main.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "ftxui/screen_interactive.hpp"
|
||||||
|
#include "ftxui/component/component.hpp"
|
||||||
|
#include "ftxui/util/string.hpp"
|
||||||
|
|
||||||
|
class DrawKey : public ftxui::component::Component {
|
||||||
|
public:
|
||||||
|
DrawKey(ftxui::component::Delegate* delegate)
|
||||||
|
: ftxui::component::Component(delegate) {}
|
||||||
|
|
||||||
|
ftxui::dom::Element Render() override {
|
||||||
|
using namespace ftxui::dom;
|
||||||
|
Children children;
|
||||||
|
for (size_t i = std::max(0, (int)keys.size() - 10); i < keys.size(); ++i) {
|
||||||
|
try {
|
||||||
|
std::string line = std::to_string(i) + " -> " + std::to_string(keys[i]) +
|
||||||
|
" (" + char(keys[i]) + ")";
|
||||||
|
children.push_back(text(to_wstring(line)));
|
||||||
|
} catch (...) {
|
||||||
|
std::string line = std::to_string(i) + " -> " + std::to_string(keys[i]) +
|
||||||
|
" (undefined)";
|
||||||
|
children.push_back(text(to_wstring(line)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vbox(std::move(children));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Event(int key) override {
|
||||||
|
keys.push_back(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<int> keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
ftxui::ScreenInteractive screen(80,10);
|
||||||
|
DrawKey draw_key(screen.delegate());
|
||||||
|
screen.Loop();
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
@ -15,7 +15,7 @@ int main(int argc, const char *argv[])
|
|||||||
center(text(L"bottom-column"))
|
center(text(L"bottom-column"))
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
auto screen = ftxui::Screen::WholeTerminal();
|
auto screen = ftxui::Screen::TerminalFullscreen();
|
||||||
Render(screen, document.get());
|
Render(screen, document.get());
|
||||||
|
|
||||||
std::cout << screen.ToString();
|
std::cout << screen.ToString();
|
||||||
|
4
examples/toggle/CMakeLists.txt
Normal file
4
examples/toggle/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
add_executable(toogle_main
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(toogle_main PRIVATE ftxui)
|
69
examples/toggle/main.cpp
Normal file
69
examples/toggle/main.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "ftxui/screen_interactive.hpp"
|
||||||
|
#include "ftxui/component/toggle.hpp"
|
||||||
|
#include "ftxui/component/component_horizontal.hpp"
|
||||||
|
#include "ftxui/component/component_vertical.hpp"
|
||||||
|
#include "ftxui/util/string.hpp"
|
||||||
|
|
||||||
|
using namespace ftxui::component;
|
||||||
|
using namespace ftxui::dom;
|
||||||
|
|
||||||
|
class MyComponent : ComponentVertical {
|
||||||
|
public:
|
||||||
|
MyComponent(ftxui::component::Delegate* delegate)
|
||||||
|
: ComponentVertical(delegate),
|
||||||
|
toggle_1(delegate->NewChild()),
|
||||||
|
toggle_2(delegate->NewChild()),
|
||||||
|
toggle_3(delegate->NewChild()) {
|
||||||
|
toggle_1.on = L"On";
|
||||||
|
toggle_1.off = L"Off";
|
||||||
|
|
||||||
|
toggle_2.on = L"Enabled";
|
||||||
|
toggle_2.off = L"Disabled";
|
||||||
|
|
||||||
|
toggle_3.on = L"10€";
|
||||||
|
toggle_3.off = L"0€";
|
||||||
|
|
||||||
|
Focus(&toggle_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<void()> on_enter = []() {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Toggle toggle_1;
|
||||||
|
Toggle toggle_2;
|
||||||
|
Toggle toggle_3;
|
||||||
|
|
||||||
|
Element Render() override {
|
||||||
|
return
|
||||||
|
vbox(
|
||||||
|
text(L"Choose your options:"),
|
||||||
|
text(L""),
|
||||||
|
hbox(text(L" * Poweroff on startup : "), toggle_1.Render()),
|
||||||
|
hbox(text(L" * Out of process : "), toggle_2.Render()),
|
||||||
|
hbox(text(L" * Price of the information : "), toggle_3.Render())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Event(int key) override {
|
||||||
|
if (ComponentVertical::Event(key))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (key == 10) {
|
||||||
|
on_enter();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
ftxui::ScreenInteractive screen(50,5);
|
||||||
|
MyComponent component(screen.delegate());
|
||||||
|
component.on_enter = screen.ExitLoopClosure();
|
||||||
|
screen.Loop();
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
@ -27,7 +27,7 @@ int main(int argc, const char *argv[])
|
|||||||
text(L"south-east")
|
text(L"south-east")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
auto screen = ftxui::Screen::WholeTerminal();
|
auto screen = ftxui::Screen::TerminalFullscreen();
|
||||||
Render(screen, document.get());
|
Render(screen, document.get());
|
||||||
|
|
||||||
std::cout << screen.ToString();
|
std::cout << screen.ToString();
|
||||||
|
@ -2,23 +2,32 @@ cmake_minimum_required(VERSION 3.0)
|
|||||||
project(ftxui)
|
project(ftxui)
|
||||||
|
|
||||||
add_library(ftxui
|
add_library(ftxui
|
||||||
src/ftxui/core/component.cpp
|
src/ftxui/component/component.cpp
|
||||||
src/ftxui/core/dom/frame.cpp
|
src/ftxui/component/component_direction.cpp
|
||||||
src/ftxui/core/dom/centered.cpp
|
src/ftxui/component/component_horizontal.cpp
|
||||||
src/ftxui/core/dom/flex.cpp
|
src/ftxui/component/component_vertical.cpp
|
||||||
src/ftxui/core/dom/frame.cpp
|
src/ftxui/component/toggle.cpp
|
||||||
src/ftxui/core/dom/gauge.cpp
|
src/ftxui/component/menu.cpp
|
||||||
src/ftxui/core/dom/hbox.cpp
|
src/ftxui/dom/bold.cpp
|
||||||
src/ftxui/core/dom/node.cpp
|
src/ftxui/dom/dim.cpp
|
||||||
src/ftxui/core/dom/separator.cpp
|
src/ftxui/dom/underlined.cpp
|
||||||
src/ftxui/core/dom/text.cpp
|
src/ftxui/dom/inverted.cpp
|
||||||
src/ftxui/core/dom/vbox.cpp
|
src/ftxui/dom/composite_decorator.cpp
|
||||||
src/ftxui/core/screen.cpp
|
src/ftxui/dom/flex.cpp
|
||||||
src/ftxui/core/terminal.cpp
|
src/ftxui/dom/frame.cpp
|
||||||
|
src/ftxui/dom/frame.cpp
|
||||||
|
src/ftxui/dom/gauge.cpp
|
||||||
|
src/ftxui/dom/hbox.cpp
|
||||||
|
src/ftxui/dom/node.cpp
|
||||||
|
src/ftxui/dom/separator.cpp
|
||||||
|
src/ftxui/dom/text.cpp
|
||||||
|
src/ftxui/dom/vbox.cpp
|
||||||
|
src/ftxui/screen.cpp
|
||||||
|
src/ftxui/screen_interactive.cpp
|
||||||
|
src/ftxui/terminal.cpp
|
||||||
src/ftxui/util/string.cpp
|
src/ftxui/util/string.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
target_include_directories(ftxui
|
target_include_directories(ftxui
|
||||||
PUBLIC include
|
PUBLIC include
|
||||||
PRIVATE src
|
PRIVATE src
|
||||||
@ -50,8 +59,9 @@ if (GTEST_FOUND AND THREADS_FOUND)
|
|||||||
endfunction(add_new_test)
|
endfunction(add_new_test)
|
||||||
|
|
||||||
add_new_test(dom_tests
|
add_new_test(dom_tests
|
||||||
src/ftxui/core/dom/text_test.cpp
|
src/ftxui/dom/gauge_test.cpp
|
||||||
src/ftxui/core/dom/hbox_test.cpp
|
src/ftxui/dom/hbox_test.cpp
|
||||||
src/ftxui/core/dom/vbox_test.cpp
|
src/ftxui/dom/text_test.cpp
|
||||||
|
src/ftxui/dom/vbox_test.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1 +1,31 @@
|
|||||||
State => Components => Document => Text.
|
#
|
||||||
|
* Level 0: terminal output.
|
||||||
|
* Level 1: ftxui::Screen
|
||||||
|
* Level 2: ftxui::dom::Node
|
||||||
|
* Level 3: ftxui::component::Component
|
||||||
|
|
||||||
|
## Level 0: terminal output.
|
||||||
|
The terminal you know, you can append text on it. It is represented by
|
||||||
|
std::cout.
|
||||||
|
|
||||||
|
## Level 1: ftxui::Screen
|
||||||
|
A rectangular grid of characters.
|
||||||
|
Use Terminal::ToString() to append its content into the console.
|
||||||
|
|
||||||
|
## Level 2: ftxui::dom::Node
|
||||||
|
A hierarchical set of element.
|
||||||
|
They handle layout and Render themself on the screen.
|
||||||
|
See ftxui/dom/elements.hpp
|
||||||
|
|
||||||
|
You can make implement your own.
|
||||||
|
|
||||||
|
## Level 3: ftxui::component::Component
|
||||||
|
A hierarchical set of component. A component render itself by producing
|
||||||
|
ftxui::dom::Node in Component::Render().
|
||||||
|
|
||||||
|
Some component can handle events:
|
||||||
|
* keyboard
|
||||||
|
* mouse
|
||||||
|
* terminal event
|
||||||
|
|
||||||
|
You can make implement your own.
|
||||||
|
34
ftxui/include/ftxui/component/Event.hpp
Normal file
34
ftxui/include/ftxui/component/Event.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_EVENT
|
||||||
|
#define FTXUI_COMPONENT_EVENT
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
struct Event{
|
||||||
|
// --- Character ---
|
||||||
|
static Event Character(char);
|
||||||
|
|
||||||
|
// --- Arrow ---
|
||||||
|
static Event Arrow_Left;
|
||||||
|
static Event Arrow_Right;
|
||||||
|
static Event Arrow_Up;
|
||||||
|
static Event Arrow_Down;
|
||||||
|
|
||||||
|
// --- Other ---
|
||||||
|
static Event Backspace;
|
||||||
|
static Event Delete;
|
||||||
|
static Event Escape;
|
||||||
|
static Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12;
|
||||||
|
|
||||||
|
// Internal representation.
|
||||||
|
int values [3];
|
||||||
|
Event(int values[3]) : values(values);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_EVENT */
|
44
ftxui/include/ftxui/component/component.hpp
Normal file
44
ftxui/include/ftxui/component/component.hpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_COMPONENT_HPP
|
||||||
|
#define FTXUI_COMPONENT_COMPONENT_HPP
|
||||||
|
|
||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
#include "ftxui/component/delegate.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
class Delegate;
|
||||||
|
class Focus;
|
||||||
|
|
||||||
|
class Component {
|
||||||
|
public:
|
||||||
|
// Constructor/Destructor.
|
||||||
|
Component(Delegate* delegate);
|
||||||
|
virtual ~Component();
|
||||||
|
|
||||||
|
// Render the component.
|
||||||
|
virtual dom::Element Render();
|
||||||
|
|
||||||
|
// Handle an event. By default, it calls this function on each children.
|
||||||
|
virtual bool Event(int key);
|
||||||
|
|
||||||
|
// If this component contains children, this indicates which one is active. It
|
||||||
|
// can be none of them.
|
||||||
|
// We say an element has the focus if the chain of GetActiveChild() from the
|
||||||
|
// root component contains this object.
|
||||||
|
virtual Component* GetActiveChild() { return nullptr; }
|
||||||
|
bool Active(); // True is this component is an active child.
|
||||||
|
bool Focused(); // True if all the ancestors are active childs.
|
||||||
|
|
||||||
|
Component* Parent();
|
||||||
|
Component* PreviousSibling();
|
||||||
|
Component* NextSibling();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Delegate* delegate_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_HPP */
|
25
ftxui/include/ftxui/component/component_direction.hpp
Normal file
25
ftxui/include/ftxui/component/component_direction.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_COMPONENT_DIRECTION_H_
|
||||||
|
#define FTXUI_COMPONENT_COMPONENT_DIRECTION_H_
|
||||||
|
|
||||||
|
#include "ftxui/component/component.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
// A component where focus and events are automatically handled for you.
|
||||||
|
class ComponentDirection : public Component {
|
||||||
|
public:
|
||||||
|
ComponentDirection(Delegate* delegate);
|
||||||
|
bool Event(int key) override;
|
||||||
|
Component* GetActiveChild() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Focus(Component* child);
|
||||||
|
virtual bool HandleDirection(int key) = 0;
|
||||||
|
Component* active_child_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_DIRECTION_H_ */
|
20
ftxui/include/ftxui/component/component_horizontal.hpp
Normal file
20
ftxui/include/ftxui/component/component_horizontal.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_COMPONENT_HORIZONTAL_H_
|
||||||
|
#define FTXUI_COMPONENT_COMPONENT_HORIZONTAL_H_
|
||||||
|
|
||||||
|
#include "ftxui/component/component_direction.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
// A component where focus and events are automatically handled for you.
|
||||||
|
// It assumes its children are put in the horizontal direction.
|
||||||
|
class ComponentHorizontal : public ComponentDirection {
|
||||||
|
public:
|
||||||
|
ComponentHorizontal(Delegate* delegate);
|
||||||
|
bool HandleDirection(int key) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_HORIZONTAL_H_ */
|
20
ftxui/include/ftxui/component/component_vertical.hpp
Normal file
20
ftxui/include/ftxui/component/component_vertical.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_COMPONENT_VERTICAL_H_
|
||||||
|
#define FTXUI_COMPONENT_COMPONENT_VERTICAL_H_
|
||||||
|
|
||||||
|
#include "ftxui/component/component_direction.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
// A component where focus and events are automatically handled for you.
|
||||||
|
// It assumes its children are put in the vertical direction.
|
||||||
|
class ComponentVertical : public ComponentDirection {
|
||||||
|
public:
|
||||||
|
ComponentVertical(Delegate* delegate);
|
||||||
|
bool HandleDirection(int key) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_VERTICAL_H_ */
|
34
ftxui/include/ftxui/component/delegate.hpp
Normal file
34
ftxui/include/ftxui/component/delegate.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_DELEGATE_HPP
|
||||||
|
#define FTXUI_COMPONENT_DELEGATE_HPP
|
||||||
|
|
||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
class Component;
|
||||||
|
|
||||||
|
class Delegate {
|
||||||
|
public:
|
||||||
|
Delegate() {}
|
||||||
|
virtual ~Delegate() {}
|
||||||
|
|
||||||
|
// A Delegate shadows a component.
|
||||||
|
virtual void Register(Component* component) = 0;
|
||||||
|
virtual Component* component() = 0;
|
||||||
|
|
||||||
|
// Create new children.
|
||||||
|
virtual Delegate* NewChild() = 0;
|
||||||
|
virtual std::vector<Delegate*> children() = 0;
|
||||||
|
|
||||||
|
// Navigate in the tree.
|
||||||
|
virtual Delegate* PreviousSibling() = 0;
|
||||||
|
virtual Delegate* NextSibling() = 0;
|
||||||
|
virtual Delegate* Parent() = 0;
|
||||||
|
virtual Delegate* Root() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_DELEGATE_HPP */
|
31
ftxui/include/ftxui/component/menu.hpp
Normal file
31
ftxui/include/ftxui/component/menu.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_MENU
|
||||||
|
#define FTXUI_COMPONENT_MENU
|
||||||
|
|
||||||
|
#include "ftxui/component/component.hpp"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
class Menu : public Component {
|
||||||
|
public:
|
||||||
|
// Constructor.
|
||||||
|
Menu(Delegate*);
|
||||||
|
|
||||||
|
// State.
|
||||||
|
std::vector<std::wstring> entries = {};
|
||||||
|
int selected = 0;
|
||||||
|
|
||||||
|
// State update callback.
|
||||||
|
std::function<void()> on_change = [](){};
|
||||||
|
std::function<void()> on_enter = [](){};
|
||||||
|
|
||||||
|
// Component implementation.
|
||||||
|
dom::Element Render() override;
|
||||||
|
bool Event(int key) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_MENU */
|
31
ftxui/include/ftxui/component/toggle.hpp
Normal file
31
ftxui/include/ftxui/component/toggle.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef FTXUI_COMPONENT_TOGGLE_H_
|
||||||
|
#define FTXUI_COMPONENT_TOGGLE_H_
|
||||||
|
|
||||||
|
#include "ftxui/component/component.hpp"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
class Toggle : public Component {
|
||||||
|
public:
|
||||||
|
// Constructor.
|
||||||
|
Toggle(Delegate*);
|
||||||
|
|
||||||
|
// State.
|
||||||
|
bool activated = true;
|
||||||
|
std::wstring on = L"On";
|
||||||
|
std::wstring off = L"Off";
|
||||||
|
|
||||||
|
// Callback.
|
||||||
|
std::function<void()> on_change = [](){};
|
||||||
|
|
||||||
|
// Component implementation.
|
||||||
|
dom::Element Render() override;
|
||||||
|
bool Event(int key) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_COMPONENT_TOGGLE_H_ */
|
@ -1,23 +0,0 @@
|
|||||||
#ifndef FTXUI_STATE_HPP
|
|
||||||
#define FTXUI_STATE_HPP
|
|
||||||
|
|
||||||
#include "ftxui/core/requirement.hpp"
|
|
||||||
#include "ftxui/core/document.hpp"
|
|
||||||
|
|
||||||
namespace ftxui {
|
|
||||||
|
|
||||||
class Component {
|
|
||||||
public:
|
|
||||||
virtual Document Render() = 0;
|
|
||||||
|
|
||||||
// Requirement -------------------------------------------------------------
|
|
||||||
virtual void ComputeRequirement();
|
|
||||||
Requirement requirement() { return requirement_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Requirement requirement_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // namespace ftxui
|
|
||||||
|
|
||||||
#endif /* end of include guard: FTXUI_STATE_HPP */
|
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef FTXUI_DOCUMENT_HPP
|
|
||||||
#define FTXUI_DOCUMENT_HPP
|
|
||||||
|
|
||||||
namespace ftxui {
|
|
||||||
|
|
||||||
class Document {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* end of include guard: FTXUI_DOCUMENT_HPP */
|
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef FTXUI_CORE_SCREEN
|
|
||||||
#define FTXUI_CORE_SCREEN
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace ftxui {
|
|
||||||
namespace dom {
|
|
||||||
class Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Screen {
|
|
||||||
public:
|
|
||||||
Screen(size_t dimx, size_t dimy);
|
|
||||||
wchar_t& at(size_t x, size_t y);
|
|
||||||
std::string ToString();
|
|
||||||
|
|
||||||
size_t dimx() { return dimx_;}
|
|
||||||
size_t dimy() { return dimy_;}
|
|
||||||
|
|
||||||
static Screen WholeTerminal();
|
|
||||||
static Screen TerminalOutput(std::unique_ptr<dom::Node>& element);
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t dimx_;
|
|
||||||
size_t dimy_;
|
|
||||||
std::vector<std::wstring> lines_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // namespace ftxui
|
|
||||||
|
|
||||||
#endif /* end of include guard: FTXUI_CORE_SCREEN */
|
|
@ -1,16 +1,14 @@
|
|||||||
#ifndef FTXUI_CORE_DOM_ELEMENTS_HPP
|
#ifndef FTXUI_DOM_ELEMENTS_HPP
|
||||||
#define FTXUI_CORE_DOM_ELEMENTS_HPP
|
#define FTXUI_DOM_ELEMENTS_HPP
|
||||||
|
|
||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
#include <initializer_list>
|
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
using Element = std::unique_ptr<Node>;
|
using Element = std::unique_ptr<Node>;
|
||||||
using Child = std::unique_ptr<Node>;
|
using Child = std::unique_ptr<Node>;
|
||||||
using Children = std::vector<std::unique_ptr<Node>>;
|
using Children = std::vector<Child>;
|
||||||
|
|
||||||
|
|
||||||
// --- Layout ----
|
// --- Layout ----
|
||||||
Element vbox(Children);
|
Element vbox(Children);
|
||||||
@ -22,7 +20,13 @@ Element text(std::wstring text);
|
|||||||
Element separator();
|
Element separator();
|
||||||
Element gauge(float ratio);
|
Element gauge(float ratio);
|
||||||
Element frame(Child);
|
Element frame(Child);
|
||||||
Element frame(std::wstring title, Child);
|
Element frame(Child title, Child content);
|
||||||
|
|
||||||
|
// -- Decorator (Style) ---
|
||||||
|
Element bold(Element);
|
||||||
|
Element dim(Element);
|
||||||
|
Element inverted(Element);
|
||||||
|
Element underlined(Element);
|
||||||
|
|
||||||
// --- Decorator ---
|
// --- Decorator ---
|
||||||
Element hcenter(Element);
|
Element hcenter(Element);
|
||||||
@ -31,23 +35,23 @@ Element center(Element);
|
|||||||
Element flex(Element);
|
Element flex(Element);
|
||||||
|
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
std::vector<Element> unpack(Args... args) {
|
Children unpack(Args... args) {
|
||||||
std::vector<Element> vec;
|
Children vec;
|
||||||
(vec.push_back(std::forward<Args>(args)), ...);
|
(vec.push_back(std::forward<Args>(args)), ...);
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
std::unique_ptr<Node> vbox(Args... children) {
|
Element vbox(Args... children) {
|
||||||
return vbox(unpack(std::forward<Args>(children)...));
|
return vbox(unpack(std::forward<Args>(children)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
std::unique_ptr<Node> hbox(Args... children) {
|
Element hbox(Args... children) {
|
||||||
return hbox(unpack(std::forward<Args>(children)...));
|
return hbox(unpack(std::forward<Args>(children)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace dom
|
}; // namespace dom
|
||||||
}; // namespace ftxui
|
}; // namespace ftxui
|
||||||
|
|
||||||
#endif /* end of include guard: FTXUI_CORE_DOM_ELEMENTS_HPP */
|
#endif /* end of include guard: FTXUI_DOM_ELEMENTS_HPP */
|
@ -1,12 +1,12 @@
|
|||||||
#ifndef CORE_DOM_NODE_HPP
|
#ifndef DOM_NODE_HPP
|
||||||
#define CORE_DOM_NODE_HPP
|
#define DOM_NODE_HPP
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ftxui/core/requirement.hpp"
|
#include "ftxui/requirement.hpp"
|
||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "ftxui/core/box.hpp"
|
#include "ftxui/box.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -41,4 +41,4 @@ void Render(Screen& screen, Node* node);
|
|||||||
}; // namespace dom
|
}; // namespace dom
|
||||||
}; // namespace ftxui
|
}; // namespace ftxui
|
||||||
|
|
||||||
#endif /* end of include guard: CORE_DOM_NODE_HPP */
|
#endif /* end of include guard: DOM_NODE_HPP */
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef FTXUI_LAYOUT_REQUIREMENT_HPP
|
#ifndef FTXUI_REQUIREMENT_HPP
|
||||||
#define FTXUI_LAYOUT_REQUIREMENT_HPP
|
#define FTXUI_REQUIREMENT_HPP
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
@ -25,4 +25,4 @@ struct Requirement {
|
|||||||
|
|
||||||
}; // namespace ftxui
|
}; // namespace ftxui
|
||||||
|
|
||||||
#endif /* end of include guard: FTXUI_LAYOUT_REQUIREMENT_HPP */
|
#endif /* end of include guard: FTXUI_REQUIREMENT_HPP */
|
55
ftxui/include/ftxui/screen.hpp
Normal file
55
ftxui/include/ftxui/screen.hpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef FTXUI_SCREEN
|
||||||
|
#define FTXUI_SCREEN
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace dom {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Pixel {
|
||||||
|
wchar_t character = U' ';
|
||||||
|
bool bold = false;
|
||||||
|
bool inverted = false;
|
||||||
|
bool underlined = false;
|
||||||
|
bool dim = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Screen {
|
||||||
|
public:
|
||||||
|
// Constructor.
|
||||||
|
Screen(size_t dimx, size_t dimy);
|
||||||
|
|
||||||
|
// Constructor using the terminal.
|
||||||
|
static Screen TerminalFullscreen();
|
||||||
|
static Screen TerminalOutput(std::unique_ptr<dom::Node>& element);
|
||||||
|
|
||||||
|
// dom::Node write into the screen using Screen::at.
|
||||||
|
wchar_t& at(size_t x, size_t y);
|
||||||
|
Pixel& PixelAt(size_t x, size_t y);
|
||||||
|
|
||||||
|
// Convert the screen into a printable string in the terminal.
|
||||||
|
std::string ToString();
|
||||||
|
|
||||||
|
// Get screen dimensions.
|
||||||
|
size_t dimx() { return dimx_;}
|
||||||
|
size_t dimy() { return dimy_;}
|
||||||
|
|
||||||
|
// Move the terminal cursor n-lines up with n = dimy().
|
||||||
|
std::string ResetPosition();
|
||||||
|
|
||||||
|
// Fill with space.
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t dimx_;
|
||||||
|
size_t dimy_;
|
||||||
|
std::vector<std::vector<Pixel>> pixels_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_SCREEN */
|
34
ftxui/include/ftxui/screen_interactive.hpp
Normal file
34
ftxui/include/ftxui/screen_interactive.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef FTXUI_SCREEN_INTERACTIVE
|
||||||
|
#define FTXUI_SCREEN_INTERACTIVE
|
||||||
|
|
||||||
|
#include "ftxui/screen.hpp"
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
|
||||||
|
namespace component {
|
||||||
|
class Delegate;
|
||||||
|
class Component;
|
||||||
|
} // namespace component
|
||||||
|
|
||||||
|
class ScreenInteractive : public Screen {
|
||||||
|
public:
|
||||||
|
ScreenInteractive(size_t dimx, size_t dimy);
|
||||||
|
~ScreenInteractive();
|
||||||
|
component::Delegate* delegate();
|
||||||
|
void Loop();
|
||||||
|
std::function<void()> ExitLoopClosure();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Delegate;
|
||||||
|
std::unique_ptr<Delegate> delegate_;
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
void Draw();
|
||||||
|
bool quit_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ftxui
|
||||||
|
|
||||||
|
#endif /* end of include guard: FTXUI_SCREEN_INTERACTIVE */
|
59
ftxui/src/ftxui/component/component.cpp
Normal file
59
ftxui/src/ftxui/component/component.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "ftxui/component/component.hpp"
|
||||||
|
#include "ftxui/component/delegate.hpp"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
Component::Component(Delegate* delegate) {
|
||||||
|
delegate_ = delegate;
|
||||||
|
delegate_->Register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Component::~Component() {}
|
||||||
|
|
||||||
|
dom::Element Component::Render() {
|
||||||
|
using namespace ftxui::dom;
|
||||||
|
return text(L"Not implemented component");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Component::Event(int key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Component::Focused() {
|
||||||
|
Delegate* current = delegate_->Root();
|
||||||
|
while (current) {
|
||||||
|
if (current == delegate_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Component* active_child = current->component()->GetActiveChild();
|
||||||
|
current = active_child ? active_child->delegate_ : nullptr;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Component::Active() {
|
||||||
|
Delegate* parent = delegate_->Parent();
|
||||||
|
return parent && parent->component()->GetActiveChild() == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component* Component::PreviousSibling() {
|
||||||
|
Delegate* sibling = delegate_->PreviousSibling();
|
||||||
|
return sibling ? sibling->component() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component* Component::NextSibling() {
|
||||||
|
Delegate* sibling = delegate_->NextSibling();
|
||||||
|
return sibling ? sibling->component() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component* Component::Parent() {
|
||||||
|
Delegate* parent_delegate = delegate_->Parent();
|
||||||
|
if (!parent_delegate)
|
||||||
|
return nullptr;
|
||||||
|
return parent_delegate->component();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
31
ftxui/src/ftxui/component/component_direction.cpp
Normal file
31
ftxui/src/ftxui/component/component_direction.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "ftxui/component/component_direction.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
ComponentDirection::ComponentDirection(Delegate* delegate)
|
||||||
|
: Component(delegate), active_child_(nullptr) {}
|
||||||
|
|
||||||
|
bool ComponentDirection::Event(int key) {
|
||||||
|
if (!Focused())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!active_child_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (active_child_->Event(key))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return HandleDirection(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Component* ComponentDirection::GetActiveChild() {
|
||||||
|
return active_child_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentDirection::Focus(Component* child) {
|
||||||
|
active_child_ = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
32
ftxui/src/ftxui/component/component_horizontal.cpp
Normal file
32
ftxui/src/ftxui/component/component_horizontal.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "ftxui/component/component_horizontal.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
ComponentHorizontal::ComponentHorizontal(Delegate* delegate)
|
||||||
|
: ComponentDirection(delegate) {}
|
||||||
|
|
||||||
|
bool ComponentHorizontal::HandleDirection(int key) {
|
||||||
|
// Left pressed ?
|
||||||
|
if (key == 68 || key == 'h') {
|
||||||
|
Component* previous_sibling = active_child_->PreviousSibling();
|
||||||
|
if (previous_sibling) {
|
||||||
|
active_child_ = previous_sibling;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left pressed ?
|
||||||
|
if (key == 67 || key == 'l') {
|
||||||
|
Component* next_sibling = active_child_->NextSibling();
|
||||||
|
if (next_sibling) {
|
||||||
|
active_child_ = next_sibling;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
32
ftxui/src/ftxui/component/component_vertical.cpp
Normal file
32
ftxui/src/ftxui/component/component_vertical.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "ftxui/component/component_vertical.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
ComponentVertical::ComponentVertical(Delegate* delegate)
|
||||||
|
: ComponentDirection(delegate) {}
|
||||||
|
|
||||||
|
bool ComponentVertical::HandleDirection(int key) {
|
||||||
|
// Up pressed ?
|
||||||
|
if (key == 65 || key == 'k') {
|
||||||
|
Component* previous_sibling = active_child_->PreviousSibling();
|
||||||
|
if (previous_sibling) {
|
||||||
|
active_child_ = previous_sibling;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down pressed ?
|
||||||
|
if (key == 66 || key == 'j') {
|
||||||
|
Component* next_sibling = active_child_->NextSibling();
|
||||||
|
if (next_sibling) {
|
||||||
|
active_child_ = next_sibling;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
53
ftxui/src/ftxui/component/menu.cpp
Normal file
53
ftxui/src/ftxui/component/menu.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "ftxui/component/menu.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
Menu::Menu(Delegate* delegate) : Component(delegate) {}
|
||||||
|
|
||||||
|
dom::Element Menu::Render() {
|
||||||
|
using namespace dom;
|
||||||
|
std::vector<Element> elements;
|
||||||
|
bool focused = Focused();
|
||||||
|
for (size_t i = 0; i < entries.size(); ++i) {
|
||||||
|
if (size_t(selected) == i) {
|
||||||
|
if (focused)
|
||||||
|
elements.push_back(inverted(text(L"> " + entries[i])));
|
||||||
|
else
|
||||||
|
elements.push_back(bold(text(L"> " + entries[i])));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elements.push_back(text(L" " + entries[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vbox(std::move(elements));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Menu::Event(int key) {
|
||||||
|
if (!Focused())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int new_selected = selected;
|
||||||
|
if (key == 65 || key == 'k')
|
||||||
|
new_selected--;
|
||||||
|
if (key == 66 || key == 'j')
|
||||||
|
new_selected++;
|
||||||
|
new_selected = std::max(0, std::min(int(entries.size())-1, new_selected));
|
||||||
|
|
||||||
|
if (selected != new_selected) {
|
||||||
|
selected = new_selected;
|
||||||
|
on_change();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == 10) {
|
||||||
|
on_enter();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
47
ftxui/src/ftxui/component/toggle.cpp
Normal file
47
ftxui/src/ftxui/component/toggle.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "ftxui/component/toggle.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace component {
|
||||||
|
|
||||||
|
Toggle::Toggle(Delegate* delegate) : Component(delegate) {}
|
||||||
|
|
||||||
|
dom::Element Toggle::Render() {
|
||||||
|
using namespace dom;
|
||||||
|
auto highlight = Focused() ? inverted : bold;
|
||||||
|
|
||||||
|
Children children;
|
||||||
|
children.push_back(text(L"["));
|
||||||
|
if (activated) {
|
||||||
|
children.push_back(highlight(text(on)));
|
||||||
|
children.push_back(text(L"|"));
|
||||||
|
children.push_back(dim(text(off)));
|
||||||
|
} else {
|
||||||
|
children.push_back(dim(text(on)));
|
||||||
|
children.push_back(text(L"|"));
|
||||||
|
children.push_back(highlight(text(off)));
|
||||||
|
}
|
||||||
|
children.push_back(text(L"]"));
|
||||||
|
return hbox(std::move(children));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Toggle::Event(int key) {
|
||||||
|
|
||||||
|
if (activated) {
|
||||||
|
if (key == 67 || key == 'l') {
|
||||||
|
activated = false;
|
||||||
|
on_change();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (key == 68 || key == 'h') {
|
||||||
|
activated = true;
|
||||||
|
on_change();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace component
|
||||||
|
} // namespace ftxui
|
@ -1,5 +0,0 @@
|
|||||||
#include "ftxui/core/component.hpp"
|
|
||||||
|
|
||||||
namespace ftxui {
|
|
||||||
void Component::ComputeRequirement() {}
|
|
||||||
} // namespace ftxui.
|
|
@ -1,57 +0,0 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
|
||||||
|
|
||||||
namespace ftxui {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
static wchar_t charset[] = L"┌┐└┘─│";
|
|
||||||
|
|
||||||
class Frame : public Node {
|
|
||||||
public:
|
|
||||||
Frame(Child child) : Node(unpack(std::move(child))) {}
|
|
||||||
~Frame() override {}
|
|
||||||
|
|
||||||
void ComputeRequirement() override {
|
|
||||||
children[0]->ComputeRequirement();
|
|
||||||
requirement_ = children[0]->requirement();
|
|
||||||
requirement_.min.x += 2;
|
|
||||||
requirement_.min.y += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetBox(Box box) override {
|
|
||||||
Node::SetBox(box);
|
|
||||||
box.left++;
|
|
||||||
box.right--;
|
|
||||||
box.top++;
|
|
||||||
box.bottom--;
|
|
||||||
children[0]->SetBox(box);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Render(Screen& screen) override {
|
|
||||||
if (box_.left >= box_.right || box_.top >= box_.bottom)
|
|
||||||
return;
|
|
||||||
|
|
||||||
screen.at(box_.left, box_.top) = charset[0];
|
|
||||||
screen.at(box_.right, box_.top) = charset[1];
|
|
||||||
screen.at(box_.left, box_.bottom) = charset[2];
|
|
||||||
screen.at(box_.right, box_.bottom) = charset[3];
|
|
||||||
for(float x = box_.left + 1; x<box_.right; ++x) {
|
|
||||||
screen.at(x, box_.top) = charset[4];
|
|
||||||
screen.at(x, box_.bottom) = charset[4];
|
|
||||||
}
|
|
||||||
for(float y = box_.top + 1; y<box_.bottom; ++y) {
|
|
||||||
screen.at(box_.left, y) = charset[5];
|
|
||||||
screen.at(box_.right,y) = charset[5];
|
|
||||||
}
|
|
||||||
children[0]->Render(screen);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
float progress_;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<Node> frame(Child child) {
|
|
||||||
return std::make_unique<Frame>(std::move(child));
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace dom
|
|
||||||
}; // namespace ftxui
|
|
@ -1,38 +0,0 @@
|
|||||||
#include "ftxui/core/screen.hpp"
|
|
||||||
#include "ftxui/core/terminal.hpp"
|
|
||||||
#include "ftxui/util/string.hpp"
|
|
||||||
#include "ftxui/core/dom/node.hpp"
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace ftxui {
|
|
||||||
|
|
||||||
Screen::Screen(size_t dimx, size_t dimy)
|
|
||||||
: dimx_(dimx), dimy_(dimy), lines_(dimy, std::wstring(dimx, U' ')) {}
|
|
||||||
|
|
||||||
std::string Screen::ToString() {
|
|
||||||
std::stringstream ss;
|
|
||||||
for (size_t y = 0; y < dimy_; ++y) {
|
|
||||||
ss << to_string(lines_[y]);
|
|
||||||
if (y + 1 < dimy_)
|
|
||||||
ss << '\n';
|
|
||||||
}
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t& Screen::at(size_t x, size_t y) {
|
|
||||||
return lines_[y][x];
|
|
||||||
}
|
|
||||||
|
|
||||||
Screen Screen::WholeTerminal() {
|
|
||||||
Terminal::Dimensions size = Terminal::Size();
|
|
||||||
return Screen(size.dimx, size.dimy);
|
|
||||||
}
|
|
||||||
|
|
||||||
Screen Screen::TerminalOutput(std::unique_ptr<dom::Node>& element) {
|
|
||||||
element->ComputeRequirement();
|
|
||||||
Terminal::Dimensions size = Terminal::Size();
|
|
||||||
return Screen(size.dimx, element->requirement().min.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace ftxui
|
|
37
ftxui/src/ftxui/dom/bold.cpp
Normal file
37
ftxui/src/ftxui/dom/bold.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "ftxui/dom/node.hpp"
|
||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class Bold : public Node {
|
||||||
|
public:
|
||||||
|
Bold(Children children) : Node(std::move(children)) {}
|
||||||
|
~Bold() override {}
|
||||||
|
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
Node::ComputeRequirement();
|
||||||
|
requirement_ = children[0]->requirement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBox(Box box) override {
|
||||||
|
Node::SetBox(box);
|
||||||
|
children[0]->SetBox(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Screen& screen) override {
|
||||||
|
Node::Render(screen);
|
||||||
|
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||||
|
for (int x = box_.left; x <= box_.right; ++x) {
|
||||||
|
screen.PixelAt(x,y).bold = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Node> bold(Child child) {
|
||||||
|
return std::make_unique<Bold>(unpack(std::move(child)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace dom
|
||||||
|
}; // namespace ftxui
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
37
ftxui/src/ftxui/dom/dim.cpp
Normal file
37
ftxui/src/ftxui/dom/dim.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "ftxui/dom/node.hpp"
|
||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class Dim : public Node {
|
||||||
|
public:
|
||||||
|
Dim(Children children) : Node(std::move(children)) {}
|
||||||
|
~Dim() override {}
|
||||||
|
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
Node::ComputeRequirement();
|
||||||
|
requirement_ = children[0]->requirement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBox(Box box) override {
|
||||||
|
Node::SetBox(box);
|
||||||
|
children[0]->SetBox(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Screen& screen) override {
|
||||||
|
Node::Render(screen);
|
||||||
|
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||||
|
for (int x = box_.left; x <= box_.right; ++x) {
|
||||||
|
screen.PixelAt(x,y).dim = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Node> dim(Child child) {
|
||||||
|
return std::make_unique<Dim>(unpack(std::move(child)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace dom
|
||||||
|
}; // namespace ftxui
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
92
ftxui/src/ftxui/dom/frame.cpp
Normal file
92
ftxui/src/ftxui/dom/frame.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "ftxui/dom/node.hpp"
|
||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
static wchar_t charset[] = L"┌┐└┘─│┬┴┤├";
|
||||||
|
|
||||||
|
class Frame : public Node {
|
||||||
|
public:
|
||||||
|
Frame(Children children) : Node(std::move(children)) {}
|
||||||
|
~Frame() override {}
|
||||||
|
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
Node::ComputeRequirement();
|
||||||
|
requirement_ = children[0]->requirement();
|
||||||
|
requirement_.min.x += 2;
|
||||||
|
requirement_.min.y += 2;
|
||||||
|
if (children.size() == 2) {
|
||||||
|
requirement_.min.x =
|
||||||
|
std::max(requirement_.min.x, children[1]->requirement().min.x + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBox(Box box) override {
|
||||||
|
Node::SetBox(box);
|
||||||
|
if (children.size() == 2) {
|
||||||
|
Box title_box;
|
||||||
|
title_box.left = box.left + 1;
|
||||||
|
title_box.right = box.right - 1;
|
||||||
|
title_box.top = box.top;
|
||||||
|
title_box.bottom = box.top;
|
||||||
|
children[1]->SetBox(title_box);
|
||||||
|
}
|
||||||
|
box.left++;
|
||||||
|
box.right--;
|
||||||
|
box.top++;
|
||||||
|
box.bottom--;
|
||||||
|
children[0]->SetBox(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Screen& screen) override {
|
||||||
|
// Draw content.
|
||||||
|
children[0]->Render(screen);
|
||||||
|
|
||||||
|
// Draw the frame.
|
||||||
|
if (box_.left >= box_.right || box_.top >= box_.bottom)
|
||||||
|
return;
|
||||||
|
|
||||||
|
screen.at(box_.left, box_.top) = charset[0];
|
||||||
|
screen.at(box_.right, box_.top) = charset[1];
|
||||||
|
screen.at(box_.left, box_.bottom) = charset[2];
|
||||||
|
screen.at(box_.right, box_.bottom) = charset[3];
|
||||||
|
for(float x = box_.left + 1; x<box_.right; ++x) {
|
||||||
|
screen.at(x, box_.top) = charset[4];
|
||||||
|
screen.at(x, box_.bottom) = charset[4];
|
||||||
|
}
|
||||||
|
for(float y = box_.top + 1; y<box_.bottom; ++y) {
|
||||||
|
screen.at(box_.left, y) = charset[5];
|
||||||
|
screen.at(box_.right,y) = charset[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to merge with separator.
|
||||||
|
for(float x = box_.left + 1; x<box_.right; ++x) {
|
||||||
|
if (screen.at(x, box_.top + 1) == charset[5])
|
||||||
|
screen.at(x, box_.top) = charset[6];
|
||||||
|
if (screen.at(x, box_.bottom - 1) == charset[5])
|
||||||
|
screen.at(x, box_.bottom) = charset[7];
|
||||||
|
}
|
||||||
|
for(float y = box_.top + 1; y<box_.bottom; ++y) {
|
||||||
|
if (screen.at(box_.left+1, y) == charset[4])
|
||||||
|
screen.at(box_.left, y) = charset[9];
|
||||||
|
if (screen.at(box_.right-1, y) == charset[4])
|
||||||
|
screen.at(box_.right,y) = charset[8];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw title.
|
||||||
|
if (children.size() == 2)
|
||||||
|
children[1]->Render(screen);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Node> frame(Child child) {
|
||||||
|
return std::make_unique<Frame>(unpack(std::move(child)));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Node> frame(Child title, Child content) {
|
||||||
|
return std::make_unique<Frame>(unpack(std::move(content), std::move(title)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace dom
|
||||||
|
}; // namespace ftxui
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
34
ftxui/src/ftxui/dom/gauge_test.cpp
Normal file
34
ftxui/src/ftxui/dom/gauge_test.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
#include "ftxui/screen.hpp"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
TEST(GaugeTest, zero) {
|
||||||
|
auto root = gauge(0);
|
||||||
|
Screen screen(11,1);
|
||||||
|
Render(screen, root.get());
|
||||||
|
|
||||||
|
EXPECT_EQ(" ", screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(GaugeTest, half) {
|
||||||
|
auto root = gauge(0.5);
|
||||||
|
Screen screen(11,1);
|
||||||
|
Render(screen, root.get());
|
||||||
|
|
||||||
|
EXPECT_EQ("█████▏▋ ", screen.ToString());
|
||||||
|
//" ▏▎▍▌▊▉█";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(GaugeTest, one) {
|
||||||
|
auto root = gauge(1.0);
|
||||||
|
Screen screen(11,1);
|
||||||
|
Render(screen, root.get());
|
||||||
|
|
||||||
|
EXPECT_EQ("███████████", screen.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace ftxui
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
37
ftxui/src/ftxui/dom/inverted.cpp
Normal file
37
ftxui/src/ftxui/dom/inverted.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "ftxui/dom/node.hpp"
|
||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class Inverted : public Node {
|
||||||
|
public:
|
||||||
|
Inverted(Children children) : Node(std::move(children)) {}
|
||||||
|
~Inverted() override {}
|
||||||
|
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
Node::ComputeRequirement();
|
||||||
|
requirement_ = children[0]->requirement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBox(Box box) override {
|
||||||
|
Node::SetBox(box);
|
||||||
|
children[0]->SetBox(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Screen& screen) override {
|
||||||
|
Node::Render(screen);
|
||||||
|
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||||
|
for (int x = box_.left; x <= box_.right; ++x) {
|
||||||
|
screen.PixelAt(x,y).inverted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Node> inverted(Child child) {
|
||||||
|
return std::make_unique<Inverted>(unpack(std::move(child)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace dom
|
||||||
|
}; // namespace ftxui
|
@ -1,4 +1,4 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -8,10 +8,15 @@ Node::Node(std::vector<std::unique_ptr<Node>> children)
|
|||||||
: children(std::move(children)) {}
|
: children(std::move(children)) {}
|
||||||
Node::~Node() {}
|
Node::~Node() {}
|
||||||
|
|
||||||
void Node::ComputeRequirement() {}
|
void Node::ComputeRequirement() {
|
||||||
|
for(auto& child : children)
|
||||||
|
child->ComputeRequirement();
|
||||||
|
}
|
||||||
|
|
||||||
void Node::SetBox(Box box) {
|
void Node::SetBox(Box box) {
|
||||||
box_ = box;
|
box_ = box;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::Render(Screen& screen) {
|
void Node::Render(Screen& screen) {
|
||||||
for(auto& child : children)
|
for(auto& child : children)
|
||||||
child->Render(screen);
|
child->Render(screen);
|
@ -1,4 +1,4 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
@ -1,4 +1,4 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
37
ftxui/src/ftxui/dom/underlined.cpp
Normal file
37
ftxui/src/ftxui/dom/underlined.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "ftxui/dom/node.hpp"
|
||||||
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class Underlined : public Node {
|
||||||
|
public:
|
||||||
|
Underlined(Children children) : Node(std::move(children)) {}
|
||||||
|
~Underlined() override {}
|
||||||
|
|
||||||
|
void ComputeRequirement() override {
|
||||||
|
Node::ComputeRequirement();
|
||||||
|
requirement_ = children[0]->requirement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBox(Box box) override {
|
||||||
|
Node::SetBox(box);
|
||||||
|
children[0]->SetBox(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Screen& screen) override {
|
||||||
|
Node::Render(screen);
|
||||||
|
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||||
|
for (int x = box_.left; x <= box_.right; ++x) {
|
||||||
|
screen.PixelAt(x,y).underlined = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Node> underlined(Child child) {
|
||||||
|
return std::make_unique<Underlined>(unpack(std::move(child)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace dom
|
||||||
|
}; // namespace ftxui
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/node.hpp"
|
#include "ftxui/dom/node.hpp"
|
||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
namespace dom {
|
namespace dom {
|
@ -1,5 +1,5 @@
|
|||||||
#include "ftxui/core/dom/elements.hpp"
|
#include "ftxui/dom/elements.hpp"
|
||||||
#include "ftxui/core/screen.hpp"
|
#include "ftxui/screen.hpp"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
91
ftxui/src/ftxui/screen.cpp
Normal file
91
ftxui/src/ftxui/screen.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "ftxui/dom/node.hpp"
|
||||||
|
#include "ftxui/screen.hpp"
|
||||||
|
#include "ftxui/terminal.hpp"
|
||||||
|
#include "ftxui/util/string.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
|
||||||
|
Screen::Screen(size_t dimx, size_t dimy)
|
||||||
|
: dimx_(dimx), dimy_(dimy), pixels_(dimy, std::vector<Pixel>(dimx)) {}
|
||||||
|
|
||||||
|
std::string Screen::ToString() {
|
||||||
|
std::wstringstream ss;
|
||||||
|
|
||||||
|
Pixel previous_pixel;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < dimy_; ++y) {
|
||||||
|
for (size_t x = 0; x < dimx_; ++x) {
|
||||||
|
if (pixels_[y][x].bold != previous_pixel.bold) {
|
||||||
|
if (pixels_[y][x].bold) {
|
||||||
|
ss << L"\e[1m";
|
||||||
|
} else {
|
||||||
|
ss << L"\e[0m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pixels_[y][x].inverted != previous_pixel.inverted) {
|
||||||
|
if (pixels_[y][x].inverted) {
|
||||||
|
ss << L"\e[7m";
|
||||||
|
} else {
|
||||||
|
ss << L"\e[27m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pixels_[y][x].underlined != previous_pixel.underlined) {
|
||||||
|
if (pixels_[y][x].underlined) {
|
||||||
|
ss << L"\e[4m";
|
||||||
|
} else {
|
||||||
|
ss << L"\e[24m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pixels_[y][x].dim != previous_pixel.dim) {
|
||||||
|
if (pixels_[y][x].dim) {
|
||||||
|
ss << L"\e[2m";
|
||||||
|
} else {
|
||||||
|
ss << L"\e[22m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss << pixels_[y][x].character;
|
||||||
|
previous_pixel = pixels_[y][x];
|
||||||
|
}
|
||||||
|
if (y + 1 < dimy_)
|
||||||
|
ss << '\n';
|
||||||
|
}
|
||||||
|
return to_string(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t& Screen::at(size_t x, size_t y) {
|
||||||
|
return pixels_[y][x].character;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pixel& Screen::PixelAt(size_t x, size_t y) {
|
||||||
|
return pixels_[y][x];
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
Screen Screen::TerminalFullscreen() {
|
||||||
|
Terminal::Dimensions size = Terminal::Size();
|
||||||
|
return Screen(size.dimx, size.dimy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
Screen Screen::TerminalOutput(std::unique_ptr<dom::Node>& element) {
|
||||||
|
element->ComputeRequirement();
|
||||||
|
Terminal::Dimensions size = Terminal::Size();
|
||||||
|
return Screen(size.dimx, element->requirement().min.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Screen::ResetPosition() {
|
||||||
|
std::stringstream ss;
|
||||||
|
for(size_t y = 1; y<dimy_; ++y) {
|
||||||
|
ss << "\e[2K\r\e[1A";
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::Clear() {
|
||||||
|
pixels_ = std::vector<std::vector<Pixel>>(dimy_,
|
||||||
|
std::vector<Pixel>(dimx_, Pixel()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace ftxui
|
112
ftxui/src/ftxui/screen_interactive.cpp
Normal file
112
ftxui/src/ftxui/screen_interactive.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include "ftxui/screen_interactive.hpp"
|
||||||
|
#include "ftxui/component/component.hpp"
|
||||||
|
#include "ftxui/component/delegate.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace ftxui {
|
||||||
|
|
||||||
|
class ScreenInteractive::Delegate : public component::Delegate {
|
||||||
|
public:
|
||||||
|
Delegate() : root_(this) {}
|
||||||
|
|
||||||
|
void Register(component::Component* c) override { component_ = c; }
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Delegate>> child_;
|
||||||
|
Delegate* NewChild() override {
|
||||||
|
Delegate* child = new Delegate;
|
||||||
|
child->root_ = root_;
|
||||||
|
child->parent_ = this;
|
||||||
|
|
||||||
|
if (!child_.empty()) {
|
||||||
|
child_.back()->next_sibling_ = child;
|
||||||
|
child->previous_sibling_ = child_.back().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
child_.emplace_back(child);
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Event(int key) { component_->Event(key); }
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<component::Delegate*> children() override {
|
||||||
|
std::vector<component::Delegate*> ret;
|
||||||
|
for (auto& it : child_)
|
||||||
|
ret.push_back(it.get());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate* root_;
|
||||||
|
Delegate* parent_ = nullptr;
|
||||||
|
Delegate* previous_sibling_ = nullptr;
|
||||||
|
Delegate* next_sibling_ = nullptr;
|
||||||
|
component::Component* component_;
|
||||||
|
|
||||||
|
Delegate* Root() override { return root_; }
|
||||||
|
Delegate* Parent() override { return parent_; }
|
||||||
|
Delegate* PreviousSibling() override { return previous_sibling_; }
|
||||||
|
Delegate* NextSibling() override { return next_sibling_; }
|
||||||
|
component::Component* component() override { return component_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
ScreenInteractive::ScreenInteractive(size_t dimx, size_t dimy)
|
||||||
|
: Screen(dimx, dimy), delegate_(new Delegate) {}
|
||||||
|
ScreenInteractive::~ScreenInteractive() {}
|
||||||
|
|
||||||
|
void ScreenInteractive::Loop() {
|
||||||
|
std::cout << "\033[?9h"; /* Send Mouse Row & Column on Button Press */
|
||||||
|
std::cout << "\033[?1000h"; /* Send Mouse X & Y on button press and release */
|
||||||
|
std::cout << std::flush;
|
||||||
|
|
||||||
|
// Save the old terminal configuration.
|
||||||
|
struct termios terminal_configuration_old;
|
||||||
|
tcgetattr(STDIN_FILENO, &terminal_configuration_old);
|
||||||
|
|
||||||
|
// Set the new terminal configuration
|
||||||
|
struct termios terminal_configuration_new;
|
||||||
|
terminal_configuration_new = terminal_configuration_old;
|
||||||
|
|
||||||
|
// Non canonique terminal.
|
||||||
|
terminal_configuration_new.c_lflag &= ~ICANON;
|
||||||
|
// Do not print after a key press.
|
||||||
|
terminal_configuration_new.c_lflag &= ~ECHO;
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_new);
|
||||||
|
|
||||||
|
Draw();
|
||||||
|
while (!quit_) {
|
||||||
|
int key = getchar();
|
||||||
|
delegate_->Event(key);
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
Draw();
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
//Clear();
|
||||||
|
|
||||||
|
// Restore the old terminal configuration.
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenInteractive::Draw() {
|
||||||
|
auto document = delegate_->component()->Render();
|
||||||
|
Render(*this, document.get());
|
||||||
|
std::cout << ToString() << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenInteractive::Clear() {
|
||||||
|
std::cout << ResetPosition();
|
||||||
|
Screen::Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
component::Delegate* ScreenInteractive::delegate() {
|
||||||
|
return delegate_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<void()> ScreenInteractive::ExitLoopClosure() {
|
||||||
|
return [this]() { quit_ = true; };
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ftxui
|
@ -2,7 +2,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "ftxui/core/terminal.hpp"
|
#include "ftxui/terminal.hpp"
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
141
tutorials/dom_elements.md
Normal file
141
tutorials/dom_elements.md
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
All the dom element are declared in one header:
|
||||||
|
"""c++
|
||||||
|
#include <ftxui/dom/elements.hpp>
|
||||||
|
"""
|
||||||
|
|
||||||
|
It declares the following set of elements:
|
||||||
|
|
||||||
|
"""C++
|
||||||
|
// --- Layout ----
|
||||||
|
Element vbox(Children);
|
||||||
|
Element hbox(Children);
|
||||||
|
Element flex();
|
||||||
|
|
||||||
|
// --- Widget --
|
||||||
|
Element text(std::wstring text);
|
||||||
|
Element separator();
|
||||||
|
Element gauge(float ratio);
|
||||||
|
Element frame(Child);
|
||||||
|
Element frame(Child title, Child content);
|
||||||
|
|
||||||
|
// -- Decorator (Style) ---
|
||||||
|
Element bold(Element);
|
||||||
|
Element dim(Element);
|
||||||
|
Element inverted(Element);
|
||||||
|
Element underlined(Element);
|
||||||
|
|
||||||
|
// --- Decorator ---
|
||||||
|
Element hcenter(Element);
|
||||||
|
Element vcenter(Element);
|
||||||
|
Element center(Element);
|
||||||
|
Element flex(Element);
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Layout elements.
|
||||||
|
|
||||||
|
vbox (Vertical-box) and hbox (Horizontal-box) are containers. They are used to
|
||||||
|
compose all the elements together. They will display their children one by one in one direction.
|
||||||
|
Each elements will occupy the space it required plus a fraction of the remaining
|
||||||
|
space dispatched to all the flexible elements.
|
||||||
|
|
||||||
|
flex() is used to make an element flexible.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
"""C++
|
||||||
|
hbox(
|
||||||
|
frame(text(L"left")),
|
||||||
|
flex(frame(text(L"middle"))),
|
||||||
|
frame(text(L"right"))
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
"""bash
|
||||||
|
┌────┐┌─────────────────────────────────────────────────────────────────┐┌─────┐
|
||||||
|
│left││middle ││right│
|
||||||
|
└────┘└─────────────────────────────────────────────────────────────────┘└─────┘
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""C++
|
||||||
|
hbox(
|
||||||
|
frame(text(L"left")),
|
||||||
|
flex(frame(text(L"middle"))),
|
||||||
|
flex(frame(text(L"right")))
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
"""bash
|
||||||
|
┌────┐┌───────────────────────────────────┐┌───────────────────────────────────┐
|
||||||
|
│left││middle ││right │
|
||||||
|
└────┘└───────────────────────────────────┘└───────────────────────────────────┘
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Widget elements.
|
||||||
|
|
||||||
|
## text
|
||||||
|
|
||||||
|
The more simple widget. It display a text.
|
||||||
|
"""C++
|
||||||
|
text(L"I am a piece of text");
|
||||||
|
"""
|
||||||
|
"""bash
|
||||||
|
I am a piece of text.
|
||||||
|
"""
|
||||||
|
|
||||||
|
## frame
|
||||||
|
Add a border arround an element
|
||||||
|
"""c+
|
||||||
|
frame(text(L"The element"))
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""bash
|
||||||
|
┌───────────┐
|
||||||
|
│The element│
|
||||||
|
└───────────┘
|
||||||
|
"""
|
||||||
|
|
||||||
|
## separator
|
||||||
|
|
||||||
|
Display a vertical or horizontal line to visually split the content of a
|
||||||
|
container in two.
|
||||||
|
|
||||||
|
"""c++
|
||||||
|
frame(hbox(
|
||||||
|
vbox(
|
||||||
|
text(L"left top"),
|
||||||
|
text(L"left bottom")
|
||||||
|
),
|
||||||
|
separator(),
|
||||||
|
vbox(
|
||||||
|
text(L"right top"),
|
||||||
|
text(L"right bottom")
|
||||||
|
)
|
||||||
|
));
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""bash
|
||||||
|
┌───────────┬────────────┐
|
||||||
|
│left top │right top │
|
||||||
|
│left bottom│right bottom│
|
||||||
|
└───────────┴────────────┘
|
||||||
|
"""
|
||||||
|
|
||||||
|
## gauge
|
||||||
|
|
||||||
|
|
||||||
|
A gauge. It can be used to represent a progress bar.
|
||||||
|
"""c+
|
||||||
|
frame(gauge(0.5))
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""bash
|
||||||
|
┌────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│██████████████████████████████████████ │
|
||||||
|
└────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Decorator (style)
|
||||||
|
A terminal console can usually display colored text and colored background.
|
||||||
|
The text can also have different effects: bold, dim, underlined, inverted.
|
||||||
|
|
||||||
|
Element bold(Element);
|
||||||
|
Element dim(Element);
|
||||||
|
Element inverted(Element);
|
||||||
|
Element underlined(Element);
|
Loading…
Reference in New Issue
Block a user