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:
Arthur Sonzogni 2018-10-09 19:06:03 +02:00
parent dd92b89611
commit 711b71688e
63 changed files with 1590 additions and 260 deletions

View File

@ -1,4 +1,8 @@
add_subdirectory(frame)
add_subdirectory(gauge)
add_subdirectory(menu)
add_subdirectory(menu2)
add_subdirectory(print_key_press)
add_subdirectory(separator)
add_subdirectory(vbox_hbox)
add_subdirectory(toggle)

View File

@ -2,33 +2,47 @@
#include <iostream>
#include <thread>
#include "ftxui/core/screen.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/screen.hpp"
#include "ftxui/dom/elements.hpp"
int main(int argc, const char *argv[])
{
using namespace ftxui::dom;
auto document =
hbox(
frame(
vbox(
text(L"Line 1"),
text(L"Line 2"),
text(L"Line 3"),
frame(
vbox(
text(L"Line 4"),
text(L"Line 5"),
text(L"Line 6")
)
),
text(L"Line 7"),
text(L"Line 8"),
text(L"Line 9")
)
),
flex()
);
auto document =
hbox(
frame(hcenter(text(L" main frame ")),
vbox(
text(L"Line 1"),
text(L"Line 2"),
text(L"Line 3"),
frame(
vbox(
text(L"Line 4"),
text(L"Line 5"),
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 8"),
text(L"Line 9")
)
)
),
text(L"footer footer footer footer footer")
)
),
flex()
);
auto screen = ftxui::Screen::TerminalOutput(document);
Render(screen, document.get());
std::cout << screen.ToString() << std::endl;

View File

@ -2,15 +2,21 @@
#include <iostream>
#include <thread>
#include "ftxui/core/screen.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/screen.hpp"
#include "ftxui/dom/elements.hpp"
int main(int argc, const char *argv[])
{
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;
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);
Render(screen, document.get());
std::cout << '\r' << screen.ToString() << std::flush;

View 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
View 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();
}

View 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
View 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();
}

View File

@ -0,0 +1,4 @@
add_executable(print_key_press
main.cpp
)
target_link_libraries(print_key_press PRIVATE ftxui)

View 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();
}

View File

@ -1,5 +1,5 @@
#include "ftxui/core/screen.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/screen.hpp"
#include "ftxui/dom/elements.hpp"
#include <iostream>
int main(int argc, const char *argv[])
@ -15,7 +15,7 @@ int main(int argc, const char *argv[])
center(text(L"bottom-column"))
))
);
auto screen = ftxui::Screen::WholeTerminal();
auto screen = ftxui::Screen::TerminalFullscreen();
Render(screen, document.get());
std::cout << screen.ToString();

View 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
View 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();
}

View File

@ -1,5 +1,5 @@
#include "ftxui/core/screen.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/screen.hpp"
#include "ftxui/dom/elements.hpp"
#include <iostream>
int main(int argc, const char *argv[])
@ -27,7 +27,7 @@ int main(int argc, const char *argv[])
text(L"south-east")
)
);
auto screen = ftxui::Screen::WholeTerminal();
auto screen = ftxui::Screen::TerminalFullscreen();
Render(screen, document.get());
std::cout << screen.ToString();

View File

@ -2,23 +2,32 @@ cmake_minimum_required(VERSION 3.0)
project(ftxui)
add_library(ftxui
src/ftxui/core/component.cpp
src/ftxui/core/dom/frame.cpp
src/ftxui/core/dom/centered.cpp
src/ftxui/core/dom/flex.cpp
src/ftxui/core/dom/frame.cpp
src/ftxui/core/dom/gauge.cpp
src/ftxui/core/dom/hbox.cpp
src/ftxui/core/dom/node.cpp
src/ftxui/core/dom/separator.cpp
src/ftxui/core/dom/text.cpp
src/ftxui/core/dom/vbox.cpp
src/ftxui/core/screen.cpp
src/ftxui/core/terminal.cpp
src/ftxui/component/component.cpp
src/ftxui/component/component_direction.cpp
src/ftxui/component/component_horizontal.cpp
src/ftxui/component/component_vertical.cpp
src/ftxui/component/toggle.cpp
src/ftxui/component/menu.cpp
src/ftxui/dom/bold.cpp
src/ftxui/dom/dim.cpp
src/ftxui/dom/underlined.cpp
src/ftxui/dom/inverted.cpp
src/ftxui/dom/composite_decorator.cpp
src/ftxui/dom/flex.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
)
target_include_directories(ftxui
PUBLIC include
PRIVATE src
@ -50,8 +59,9 @@ if (GTEST_FOUND AND THREADS_FOUND)
endfunction(add_new_test)
add_new_test(dom_tests
src/ftxui/core/dom/text_test.cpp
src/ftxui/core/dom/hbox_test.cpp
src/ftxui/core/dom/vbox_test.cpp
src/ftxui/dom/gauge_test.cpp
src/ftxui/dom/hbox_test.cpp
src/ftxui/dom/text_test.cpp
src/ftxui/dom/vbox_test.cpp
)
endif()

View File

@ -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.

View 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 */

View 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 */

View 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_ */

View 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_ */

View 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_ */

View 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 */

View 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 */

View 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_ */

View File

@ -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 */

View File

@ -1,12 +0,0 @@
#ifndef FTXUI_DOCUMENT_HPP
#define FTXUI_DOCUMENT_HPP
namespace ftxui {
class Document {
};
};
#endif /* end of include guard: FTXUI_DOCUMENT_HPP */

View File

@ -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 */

View File

@ -1,16 +1,14 @@
#ifndef FTXUI_CORE_DOM_ELEMENTS_HPP
#define FTXUI_CORE_DOM_ELEMENTS_HPP
#ifndef FTXUI_DOM_ELEMENTS_HPP
#define FTXUI_DOM_ELEMENTS_HPP
#include "ftxui/core/dom/node.hpp"
#include <initializer_list>
#include "ftxui/dom/node.hpp"
namespace ftxui {
namespace dom {
using Element = std::unique_ptr<Node>;
using Child = std::unique_ptr<Node>;
using Children = std::vector<std::unique_ptr<Node>>;
using Children = std::vector<Child>;
// --- Layout ----
Element vbox(Children);
@ -22,7 +20,13 @@ Element text(std::wstring text);
Element separator();
Element gauge(float ratio);
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 ---
Element hcenter(Element);
@ -31,23 +35,23 @@ Element center(Element);
Element flex(Element);
template <class... Args>
std::vector<Element> unpack(Args... args) {
std::vector<Element> vec;
Children unpack(Args... args) {
Children vec;
(vec.push_back(std::forward<Args>(args)), ...);
return vec;
}
template <class... Args>
std::unique_ptr<Node> vbox(Args... children) {
Element vbox(Args... children) {
return vbox(unpack(std::forward<Args>(children)...));
}
template <class... Args>
std::unique_ptr<Node> hbox(Args... children) {
Element hbox(Args... children) {
return hbox(unpack(std::forward<Args>(children)...));
}
}; // namespace dom
}; // namespace ftxui
#endif /* end of include guard: FTXUI_CORE_DOM_ELEMENTS_HPP */
#endif /* end of include guard: FTXUI_DOM_ELEMENTS_HPP */

View File

@ -1,12 +1,12 @@
#ifndef CORE_DOM_NODE_HPP
#define CORE_DOM_NODE_HPP
#ifndef DOM_NODE_HPP
#define DOM_NODE_HPP
#include <memory>
#include <vector>
#include "ftxui/core/requirement.hpp"
#include "ftxui/core/screen.hpp"
#include "ftxui/core/box.hpp"
#include "ftxui/requirement.hpp"
#include "ftxui/screen.hpp"
#include "ftxui/box.hpp"
namespace ftxui {
namespace dom {
@ -41,4 +41,4 @@ void Render(Screen& screen, Node* node);
}; // namespace dom
}; // namespace ftxui
#endif /* end of include guard: CORE_DOM_NODE_HPP */
#endif /* end of include guard: DOM_NODE_HPP */

View File

@ -1,5 +1,5 @@
#ifndef FTXUI_LAYOUT_REQUIREMENT_HPP
#define FTXUI_LAYOUT_REQUIREMENT_HPP
#ifndef FTXUI_REQUIREMENT_HPP
#define FTXUI_REQUIREMENT_HPP
namespace ftxui {
@ -25,4 +25,4 @@ struct Requirement {
}; // namespace ftxui
#endif /* end of include guard: FTXUI_LAYOUT_REQUIREMENT_HPP */
#endif /* end of include guard: FTXUI_REQUIREMENT_HPP */

View 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 */

View 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 */

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -1,5 +0,0 @@
#include "ftxui/core/component.hpp"
namespace ftxui {
void Component::ComputeRequirement() {}
} // namespace ftxui.

View File

@ -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

View File

@ -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

View 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

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
namespace dom {

View 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

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
namespace dom {

View 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

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
namespace dom {

View 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

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
namespace dom {

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/core/screen.hpp"
#include "ftxui/dom/elements.hpp"
#include "ftxui/screen.hpp"
#include "gtest/gtest.h"
namespace ftxui {

View 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

View File

@ -1,4 +1,4 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/dom/node.hpp"
namespace ftxui {
namespace dom {
@ -8,10 +8,15 @@ Node::Node(std::vector<std::unique_ptr<Node>> children)
: children(std::move(children)) {}
Node::~Node() {}
void Node::ComputeRequirement() {}
void Node::ComputeRequirement() {
for(auto& child : children)
child->ComputeRequirement();
}
void Node::SetBox(Box box) {
box_ = box;
}
void Node::Render(Screen& screen) {
for(auto& child : children)
child->Render(screen);

View File

@ -1,4 +1,4 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/dom/node.hpp"
namespace ftxui {
namespace dom {

View File

@ -1,4 +1,4 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/dom/node.hpp"
namespace ftxui {
namespace dom {

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/core/screen.hpp"
#include "ftxui/dom/elements.hpp"
#include "ftxui/screen.hpp"
#include "gtest/gtest.h"
namespace ftxui {

View 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

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/node.hpp"
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
namespace dom {

View File

@ -1,5 +1,5 @@
#include "ftxui/core/dom/elements.hpp"
#include "ftxui/core/screen.hpp"
#include "ftxui/dom/elements.hpp"
#include "ftxui/screen.hpp"
#include "gtest/gtest.h"
namespace ftxui {

View 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

View 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

View File

@ -2,7 +2,7 @@
#include <stdio.h>
#include <unistd.h>
#include "ftxui/core/terminal.hpp"
#include "ftxui/terminal.hpp"
namespace ftxui {

141
tutorials/dom_elements.md Normal file
View 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);