Add support for nxxm.

[nxxm](https://nxxm.github.io)
This commit is contained in:
ArthurSonzogni
2019-02-02 01:59:48 +01:00
parent 2eddd0fa17
commit ef0de8d873
72 changed files with 309 additions and 165 deletions

31
include/ftxui/README.md Normal file
View File

@@ -0,0 +1,31 @@
#
* Level 0: terminal output.
* Level 1: ftxui::Screen
* Level 2: ftxui::Node
* Level 3: ftxui::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::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
A hierarchical set of component. A component render itself by producing
ftxui::Node in Component::Render().
Some component can handle events:
* keyboard
* mouse
* terminal event
Implement your own!

View File

@@ -0,0 +1,39 @@
#ifndef FTXUI_COMPONENT_CHECKBOX_HPP
#define FTXUI_COMPONENT_CHECKBOX_HPP
#include "ftxui/component/component.hpp"
#include <functional>
namespace ftxui {
class CheckBox : public Component {
public:
// Constructor.
CheckBox() = default;
~CheckBox() override = default;
bool state = false;
std::wstring label = L"label";
//std::wstring checked = L"[X] ";
//std::wstring unchecked = L"[ ] ";
std::wstring checked = L"";
std::wstring unchecked = L"";
Decorator focused_style = inverted;
Decorator unfocused_style = nothing;
// State update callback.
std::function<void()> on_change = [](){};
// Component implementation.
Element Render() override;
bool OnEvent(Event) override;
private:
int cursor_position = 0;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_COMPONENT_CHECKBOX_HPP */

View File

@@ -0,0 +1,56 @@
#ifndef FTXUI_COMPONENT_COMPONENT_HPP
#define FTXUI_COMPONENT_COMPONENT_HPP
#include "ftxui/component/event.hpp"
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class Delegate;
class Focus;
class Component {
public:
// Constructor/Destructor.
Component() = default;
virtual ~Component();
// Component hierarchy.
Component* Parent() { return parent_; }
void Add(Component* children);
// Renders the component.
virtual Element Render();
// Handles an event.
// By default, reduce on children with a lazy OR.
//
// Returns whether the event was handled or not.
virtual bool OnEvent(Event);
// Focus management ----------------------------------------------------------
//
// If this component contains children, this indicates which one is active,
// nullptr if none is active.
//
// We say an element has the focus if the chain of ActiveChild() from the
// root component contains this object.
virtual Component* ActiveChild();
// Whether this is the active child of its parent.
bool Active();
// Whether all the ancestors are active.
bool Focused();
private:
Component* parent_ = nullptr;
void Detach();
void Attach(Component* parent);
protected:
std::vector<Component*> children_;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_HPP */

View File

@@ -0,0 +1,45 @@
#ifndef FTXUI_COMPONENT_CONTAINER_HPP
#define FTXUI_COMPONENT_CONTAINER_HPP
#include "ftxui/component/component.hpp"
namespace ftxui {
// A component where focus and events are automatically handled for you.
// List of container:
//
// Please use HorizontalContainer or VerticalContainer.
class Container : public Component {
public:
static Container Vertical();
static Container Horizontal();
static Container Tab(int* selector);
~Container() override = default;
// Component override.
bool OnEvent(Event event) override;
Element Render() override;
Component* ActiveChild() override;
protected:
// Handlers
using EventHandler = bool (Container::*)(Event);
bool VerticalEvent(Event event);
bool HorizontalEvent(Event event);
bool TabEvent(Event event) { return false; }
EventHandler event_handler_;
using RenderHandler = Element (Container::*)();
Element VerticalRender();
Element HorizontalRender();
Element TabRender();
RenderHandler render_handler_;
int selected_ = 0;
int* selector_ = &selected_;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_COMPONENT_CONTAINER_HPP */

View File

@@ -0,0 +1,41 @@
#ifndef FTXUI_COMPONENT_EVENT_HPP
#define FTXUI_COMPONENT_EVENT_HPP
#include <vector>
#include <array>
namespace ftxui {
struct Event{
public:
// --- Character ---
static Event Character(int);
// --- Arrow ---
static Event ArrowLeft;
static Event ArrowRight;
static Event ArrowUp;
static Event ArrowDown;
// --- Other ---
static Event Backspace;
static Event Delete;
static Event Return;
static Event Escape;
static Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12;
// --- Custom ---
static Event Custom;
bool operator==(const Event& other) { return values == other.values; }
// Internal representation.
std::array<int, 5> values = {0, 0, 0, 0, 0};
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_COMPONENT_EVENT_HPP */

View File

@@ -0,0 +1,33 @@
#ifndef FTXUI_COMPONENT_INPUT_H_
#define FTXUI_COMPONENT_INPUT_H_
#include "ftxui/component/component.hpp"
#include <functional>
namespace ftxui {
class Input : public Component {
public:
// Constructor.
Input() = default;
~Input() override = default;
// State.
std::wstring content;
std::wstring placeholder;
// State update callback.
std::function<void()> on_change = [](){};
std::function<void()> on_enter = [](){};
// Component implementation.
Element Render() override;
bool OnEvent(Event) override;
private:
int cursor_position = 0;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_COMPONENT_INPUT_H_ */

View File

@@ -0,0 +1,35 @@
#ifndef FTXUI_COMPONENT_MENU
#define FTXUI_COMPONENT_MENU
#include "ftxui/component/component.hpp"
#include "ftxui/dom/elements.hpp"
#include <functional>
namespace ftxui {
class Menu : public Component {
public:
// Constructor.
Menu() = default;
~Menu() override = default;
// State.
std::vector<std::wstring> entries = {};
int selected = 0;
Decorator focused_style = inverted;
Decorator selected_style = bold;
Decorator normal_style = nothing;
// State update callback.
std::function<void()> on_change = [](){};
std::function<void()> on_enter = [](){};
// Component implementation.
Element Render() override;
bool OnEvent(Event) override;
};
} // namespace ftxui::Component
#endif /* end of include guard: FTXUI_COMPONENT_MENU */

View File

@@ -0,0 +1,38 @@
#ifndef FTXUI_COMPONENT_RADIOBOX_HPP
#define FTXUI_COMPONENT_RADIOBOX_HPP
#include "ftxui/component/component.hpp"
#include <functional>
namespace ftxui {
class RadioBox : public Component {
public:
// Constructor.
RadioBox() = default;
~RadioBox() override = default;
int selected = 0;
int focused = 0;
std::vector<std::wstring> entries;
std::wstring checked = L"";
std::wstring unchecked = L"";
Decorator focused_style = inverted;
Decorator unfocused_style = nothing;
// State update callback.
std::function<void()> on_change = [](){};
// Component implementation.
Element Render() override;
bool OnEvent(Event) override;
private:
int cursor_position = 0;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_COMPONENT_RADIOBOX_HPP */

View File

@@ -0,0 +1,51 @@
#ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <atomic>
#include "ftxui/component/event.hpp"
#include "ftxui/screen/screen.hpp"
namespace ftxui {
class Component;
class ScreenInteractive : public Screen {
public:
static ScreenInteractive FixedSize(int dimx, int dimy);
static ScreenInteractive Fullscreen();
static ScreenInteractive FitComponent();
static ScreenInteractive TerminalOutput();
~ScreenInteractive();
void Loop(Component*);
std::function<void()> ExitLoopClosure();
void PostEvent(Event event);
private:
void Draw(Component* component);
void EventLoop(Component* component);
enum class Dimension {
FitComponent,
Fixed,
Fullscreen,
TerminalOutput,
};
Dimension dimension_ = Dimension::Fixed;
ScreenInteractive(int dimx, int dimy, Dimension dimension);
std::condition_variable events_queue_wait;
std::mutex events_queue_mutex;
std::queue<Event> events_queue;
std::atomic<bool> quit_ = false;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP */

View File

@@ -0,0 +1,33 @@
#ifndef FTXUI_COMPONENT_TOGGLE_H_
#define FTXUI_COMPONENT_TOGGLE_H_
#include "ftxui/component/component.hpp"
#include <functional>
#include <string>
namespace ftxui {
class Toggle : public Component {
public:
// Constructor.
~Toggle() override = default;
// State.
int selected = 0;
std::vector<std::wstring> entries = {L"On", L"Off"};
Decorator focused_style = inverted;
Decorator selected_style = bold;
Decorator normal_style = dim;
// Callback.
std::function<void()> on_change = [](){};
// Component implementation.
Element Render() override;
bool OnEvent(Event) override;
};
} // namespace ftxui::Component
#endif /* end of include guard: FTXUI_COMPONENT_TOGGLE_H_ */

View File

@@ -0,0 +1,88 @@
#ifndef FTXUI_DOM_ELEMENTS_HPP
#define FTXUI_DOM_ELEMENTS_HPP
#include <functional>
#include "ftxui/dom/node.hpp"
#include "ftxui/screen/color.hpp"
namespace ftxui {
using Element = std::unique_ptr<Node>;
using Elements = std::vector<Element>;
using Decorator = std::function<Element(Element)>;
using GraphFunction = std::function<std::vector<int>(int,int)>;
// --- Widget ---
Element text(std::wstring text);
Element separator();
Element separator(Pixel);
Element gauge(float ratio);
Element border(Element);
Decorator borderWith(Pixel);
Element window(Element title, Element content);
Element spinner(int charset_index, size_t image_index);
Elements paragraph(std::wstring text); // Use inside hflow(). Split by space.
Element graph(GraphFunction);
// -- Decorator ---
Element bold(Element);
Element dim(Element);
Element inverted(Element);
Element underlined(Element);
Element blink(Element);
Decorator color(Color);
Decorator bgcolor(Color);
Element color(Color, Element);
Element bgcolor(Color, Element);
// --- Layout ---
// Horizontal, Vertical or stacked set of elements.
Element hbox(Elements);
Element vbox(Elements);
Element dbox(Elements);
Element hflow(Elements);
// -- Flexibility ---
// Define how to share the remaining space when not all of it is used inside a
// container.
Element filler();
Element flex(Element);
Element notflex(Element);
// -- Size override;
enum Direction { WIDTH, HEIGHT };
enum Constraint { LESS_THAN, EQUAL, GREATER_THAN };
Decorator size(Direction, Constraint, int value);
// --- Frame ---
// A frame is a scrollable area. The internal area is potentially larger than
// the external one. The internal area is scrolled in order to make visible the
// focused element.
Element frame(Element);
Element focus(Element);
Element select(Element);
// --- Util --------------------------------------------------------------------
Element hcenter(Element);
Element vcenter(Element);
Element center(Element);
Element align_right(Element);
Element nothing(Element element);
// Pipe elements into decorator togethers.
// Examples: text("ftxui") | bold | underlined;
Element operator|(Element, Decorator);
Elements operator|(Elements, Decorator);
Decorator operator|(Decorator, Decorator);
// Make container able to take any number of children as input.
#include "take_any_args.hpp"
TAKE_ANY_ARGS(vbox)
TAKE_ANY_ARGS(hbox)
TAKE_ANY_ARGS(dbox)
TAKE_ANY_ARGS(hflow)
}; // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_ELEMENTS_HPP */

View File

@@ -0,0 +1,42 @@
#ifndef FTXUI_DOM_NODE_HPP
#define FTXUI_DOM_NODE_HPP
#include <memory>
#include <vector>
#include "ftxui/dom/requirement.hpp"
#include "ftxui/screen/box.hpp"
#include "ftxui/screen/screen.hpp"
namespace ftxui {
class Node {
public:
Node();
Node(std::vector<std::unique_ptr<Node>> children);
virtual ~Node();
// Step 1: Compute layout requirement. Tell parent what dimensions this
// element wants to be.
// Propagated from Children to Parents.
virtual void ComputeRequirement();
Requirement requirement() { return requirement_; }
// Step 2: Assign this element its final dimensions.
// Propagated from Parents to Children.
virtual void SetBox(Box box);
// Step 3: Draw this element.
virtual void Render(Screen& screen);
std::vector<std::unique_ptr<Node>> children;
protected:
Requirement requirement_;
Box box_;
};
void Render(Screen& screen, Node* node);
}; // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_NODE_HPP */

View File

@@ -0,0 +1,26 @@
#ifndef FTXUI_DOM_REQUIREMENT_HPP
#define FTXUI_DOM_REQUIREMENT_HPP
#include "ftxui/screen/box.hpp"
namespace ftxui {
struct Requirement {
// The required size to fully draw the element.
struct { int x = 0; int y = 0; } min;
// How much flexibility is given to the component.
struct { int x = 0; int y = 0; } flex;
// Frame.
enum Selection {
NORMAL = 0,
SELECTED = 1,
FOCUSED = 2,
} selection = NORMAL;
Box selected_box;
};
}; // namespace ftxui
#endif /* end of include guard: FTXUI_REQUIREMENT_HPP */

View File

@@ -0,0 +1,30 @@
#include <type_traits>
template <class T>
void Merge(Elements& container, T t) {}
template <>
inline void Merge(Elements& container, Element element) {
container.push_back(std::move(element));
}
template <>
inline void Merge(Elements& container, Elements elements) {
for(auto& element : elements)
container.push_back(std::move(element));
}
// Turn a set of arguments into a vector.
template <class... Args>
Elements unpack(Args... args) {
std::vector<Element> vec;
(Merge(vec, std::move(args)), ...);
return vec;
}
// Make |container| able to take any number of argments.
#define TAKE_ANY_ARGS(container) \
template <class... Args> \
Element container(Args... children) { \
return container(unpack(std::forward<Args>(children)...)); \
}

View File

@@ -0,0 +1,17 @@
#ifndef FTXUI_SCREEN_BOX_HPP
#define FTXUI_SCREEN_BOX_HPP
namespace ftxui {
struct Box {
int x_min;
int x_max;
int y_min;
int y_max;
static Box Intersection(Box a, Box b);
};
}; // namespace ftxui
#endif /* end of include guard: FTXUI_SCREEN_BOX_HPP */

View File

@@ -0,0 +1,40 @@
#ifndef FTXUI_SCREEN_COLOR
#define FTXUI_SCREEN_COLOR
#include <cstdint>
namespace ftxui {
enum class Color : uint8_t {
// --- Transparent -----
Default = 39,
// --- Grayscale -----
Black = 30,
GrayDark = 90,
GrayLight = 37,
White = 97,
// --- Hue -----
Blue = 34,
BlueLight = 94,
Cyan = 36,
CyanLight = 96,
Green = 32,
GreenLight = 92,
Magenta = 35,
MagentaLight = 95,
Red = 31,
RedLight = 91,
Yellow = 33,
YellowLight = 93,
};
}; // namespace ftxui
#endif /* end of include guard: FTXUI_COLOR_H_ */

View File

@@ -0,0 +1,72 @@
#ifndef FTXUI_SCREEN_SCREEN
#define FTXUI_SCREEN_SCREEN
#include <string>
#include <vector>
#include <memory>
#include "ftxui/screen/color.hpp"
#include "ftxui/screen/box.hpp"
namespace ftxui {
class Node;
}
namespace ftxui {
struct Pixel {
wchar_t character = U' ';
bool blink = false;
bool bold = false;
bool dim = false;
bool inverted = false;
bool underlined = false;
Color background_color = Color::Default;
Color foreground_color = Color::Default;
};
struct Dimension {
static Dimension Fixed(int);
static Dimension Fit(std::unique_ptr<Node>&);
static Dimension Full();
int dimx;
int dimy;
};
class Screen {
public:
// Constructor.
Screen(int dimx, int dimy);
static Screen Create(Dimension dimension);
static Screen Create(Dimension width, Dimension height);
// Node write into the screen using Screen::at.
wchar_t& at(int x, int y);
Pixel& PixelAt(int x, int y);
// Convert the screen into a printable string in the terminal.
std::string ToString();
// Get screen dimensions.
int dimx() { return dimx_;}
int dimy() { return dimy_;}
// Move the terminal cursor n-lines up with n = dimy().
std::string ResetPosition();
// Fill with space.
void Clear();
void ApplyShader();
Box stencil;
protected:
int dimx_;
int dimy_;
std::vector<std::vector<Pixel>> pixels_;
};
}; // namespace ftxui
#endif /* end of include guard: FTXUI_SCREEN_SCREEN */

View File

@@ -0,0 +1,9 @@
#include <string>
std::string to_string(const std::wstring& s);
std::wstring to_wstring(const std::string& s);
template<typename T>
std::wstring to_wstring(T s) {
return to_wstring(std::to_string(s));
}

View File

@@ -0,0 +1,22 @@
#ifndef FTXUI_UTIL_AUTORESET_HPP
#define FTXUI_UTIL_AUTORESET_HPP
namespace ftxui {
template<typename T>
class AutoReset {
public:
AutoReset(T* variable, T new_value)
: variable_(variable),
previous_value_(std::move(*variable)) {
*variable_ = std::move(new_value);
}
~AutoReset() { *variable_ = std::move(previous_value_); }
private:
T* variable_;
T previous_value_;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_UTIL_AUTORESET_HPP */