Add example homepage.cpp

This commit is contained in:
ArthurSonzogni
2019-01-27 02:33:06 +01:00
parent 9117166541
commit eacb634a9e
15 changed files with 422 additions and 57 deletions

View File

@@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.0)
find_package(Threads)
add_library(screen
src/ftxui/screen/box.cpp
@@ -48,7 +49,7 @@ add_library(component
target_link_libraries(dom PUBLIC screen)
target_link_libraries(component PUBLIC dom)
target_link_libraries(component PUBLIC Threads::Threads)
foreach(lib screen dom component)
target_include_directories(${lib}
@@ -86,7 +87,6 @@ install(EXPORT ftxui-export
# Note: For gtest, please follow:
# https://stackoverflow.com/questions/24295876/cmake-cannot-find-a-googletest-required-library
find_package(GTest)
find_package(Threads)
if (GTEST_FOUND AND THREADS_FOUND)
add_executable(dom_tests
src/ftxui/dom/gauge_test.cpp

View File

@@ -24,10 +24,14 @@ struct Event{
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};
};

View File

@@ -1,9 +1,15 @@
#ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#include "ftxui/screen/screen.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;
@@ -19,9 +25,11 @@ class ScreenInteractive : public Screen {
void Loop(Component*);
std::function<void()> ExitLoopClosure();
void PostEvent(Event event);
private:
void Draw(Component* component);
bool quit_ = false;
void EventLoop(Component* component);
enum class Dimension {
FitComponent,
@@ -31,6 +39,11 @@ class ScreenInteractive : public Screen {
};
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

View File

@@ -3,7 +3,6 @@
#include <functional>
#include "ftxui/dom/graph.hpp"
#include "ftxui/dom/node.hpp"
#include "ftxui/screen/color.hpp"
@@ -12,16 +11,19 @@ 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&); // See graph.hpp
Element graph(GraphFunction);
// -- Decorator ---
Element bold(Element);
@@ -46,6 +48,7 @@ Element hflow(Elements);
// container.
Element filler();
Element flex(Element);
Element notflex(Element);
// -- Size override;
enum Direction { WIDTH, HEIGHT };

View File

@@ -1,15 +0,0 @@
#ifndef FTXUI_DOM_GRAPH_HPP
#define FTXUI_DOM_GRAPH_HPP
#include "ftxui/dom/elements.hpp"
namespace ftxui {
class GraphFunction {
public:
virtual std::vector<int> operator()(int width, int height) = 0;
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_GRAPH_HPP */

View File

@@ -34,4 +34,6 @@ Event Event::F10{ESC, '[', '2', '1', '~'};
Event Event::F11{ESC, '[', '2', '1', '~'}; // Same as F10 ?
Event Event::F12{ESC, '[', '2', '4', '~'};
Event Event::Custom{0, 0, 0, 0, 0};
} // namespace ftxui

View File

@@ -5,19 +5,21 @@ namespace ftxui {
// Component implementation.
Element Input::Render() {
cursor_position = std::max(0, std::min<int>(content.size(), cursor_position));
auto main_decorator = flex | size(HEIGHT, EQUAL, 1);
bool is_focused = Focused();
// Placeholder.
if (content.size() == 0) {
if (is_focused)
return text(placeholder) | dim | inverted | flex;
return text(placeholder) | dim | inverted | main_decorator;
else
return text(placeholder) | dim | flex;
return text(placeholder) | dim | main_decorator;
}
// Not focused.
if (!is_focused)
return text(content) | flex;
return text(content) | main_decorator;
std::wstring part_before_cursor = content.substr(0,cursor_position);
std::wstring part_at_cursor = cursor_position < (int)content.size()
@@ -34,9 +36,11 @@ Element Input::Render() {
text(part_before_cursor),
text(part_at_cursor) | underlined | focused,
text(part_after_cursor)
) | flex | inverted | frame;
) | flex | inverted | frame | main_decorator;
}
bool Input::OnEvent(Event event) {
cursor_position = std::max(0, std::min<int>(content.size(), cursor_position));
std::wstring c;
// Backspace.
@@ -50,9 +54,14 @@ bool Input::OnEvent(Event event) {
// Enter.
if (event == Event::Return) {
on_enter();
return true;
}
if (event == Event::Custom) {
return false;
}
if (event == Event::ArrowLeft && cursor_position > 0) {
cursor_position--;
return true;

View File

@@ -6,6 +6,7 @@
#include <iostream>
#include "ftxui/component/component.hpp"
#include "ftxui/screen/terminal.hpp"
#include <thread>
namespace ftxui {
@@ -70,6 +71,28 @@ ScreenInteractive ScreenInteractive::FitComponent() {
return ScreenInteractive(0, 0, Dimension::FitComponent);
}
void ScreenInteractive::PostEvent(Event event) {
std::unique_lock<std::mutex> lock(events_queue_mutex);
events_queue.push(event);
events_queue_wait.notify_one();
}
void ScreenInteractive::EventLoop(Component* component) {
bool handled = 0;
for (;;) {
std::unique_lock<std::mutex> lock(events_queue_mutex);
while (!events_queue.empty()) {
component->OnEvent(events_queue.front());
events_queue.pop();
handled = true;
}
if (handled)
return;
events_queue_wait.wait(lock);
}
}
void ScreenInteractive::Loop(Component* component) {
//std::cout << "\033[?9h"; [> Send Mouse Row & Column on Button Press <]
//std::cout << "\033[?1000h"; [> Send Mouse X & Y on button press and release <]
@@ -89,18 +112,25 @@ void ScreenInteractive::Loop(Component* component) {
terminal_configuration_new.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_new);
std::thread read_char([this]() {
while (!quit_)
PostEvent(GetEvent());
});
std::string reset_position;
while (!quit_) {
reset_position = ResetPosition();
Draw(component);
std::cout << reset_position << ToString() << std::flush;
Clear();
component->OnEvent(GetEvent());
EventLoop(component);
}
// Restore the old terminal configuration.
tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old);
read_char.join();
std::cout << std::endl;
}

View File

@@ -5,13 +5,21 @@ namespace ftxui {
using namespace ftxui;
static wchar_t charset[] = L"┌┐└┘─│┬┴┤├";
static wchar_t simple_border_charset[] = L"┌┐└┘─│┬┴┤├";
class Border : public Node {
public:
Border(Elements children) : Node(std::move(children)) {}
Border(Elements children)
: Node(std::move(children)),
charset(std::begin(simple_border_charset),
std::end(simple_border_charset)) {}
Border(Elements children, Pixel pixel)
: Node(std::move(children)), charset_pixel(10, pixel) {}
~Border() override {}
std::vector<Pixel> charset_pixel;
std::vector<wchar_t> charset;
void ComputeRequirement() override {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
@@ -52,6 +60,13 @@ class Border : public Node {
if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max)
return;
if (!charset.empty())
RenderPixel(screen);
else
RenderChar(screen);
}
void RenderPixel(Screen& screen) {
screen.at(box_.x_min, box_.y_min) = charset[0];
screen.at(box_.x_max, box_.y_min) = charset[1];
screen.at(box_.x_min, box_.y_max) = charset[2];
@@ -69,6 +84,21 @@ class Border : public Node {
if (children.size() == 2)
children[1]->Render(screen);
}
void RenderChar(Screen& screen) {
screen.PixelAt(box_.x_min, box_.y_min) = charset_pixel[0];
screen.PixelAt(box_.x_max, box_.y_min) = charset_pixel[1];
screen.PixelAt(box_.x_min, box_.y_max) = charset_pixel[2];
screen.PixelAt(box_.x_max, box_.y_max) = charset_pixel[3];
for(float x = box_.x_min + 1; x<box_.x_max; ++x) {
screen.PixelAt(x, box_.y_min) = charset_pixel[4];
screen.PixelAt(x, box_.y_max) = charset_pixel[4];
}
for(float y = box_.y_min + 1; y<box_.y_max; ++y) {
screen.PixelAt(box_.x_min, y) = charset_pixel[5];
screen.PixelAt(box_.x_max,y) = charset_pixel[5];
}
}
};
std::unique_ptr<Node> border(Element child) {
@@ -79,9 +109,9 @@ std::unique_ptr<Node> window(Element title, Element content) {
return std::make_unique<Border>(unpack(std::move(content), std::move(title)));
}
Decorator boxed() {
return [](Element child) {
return border(std::move(child));
Decorator borderWith(Pixel pixel) {
return [pixel](Element child) {
return std::make_unique<Border>(unpack(std::move(child)), pixel);
};
}

View File

@@ -8,7 +8,7 @@ class Flex : public Node {
Flex() {}
Flex(Element child) : Node(unpack(std::move(child))) {}
~Flex() override {}
void ComputeRequirement() {
void ComputeRequirement() override {
requirement_.min.x = 0;
requirement_.min.y = 0;
if (!children.empty()) {
@@ -26,6 +26,23 @@ class Flex : public Node {
}
};
class NotFlex : public Flex {
public:
NotFlex() {}
NotFlex(Element child) : Flex(std::move(child)) {}
~NotFlex() override {}
void ComputeRequirement() override {
requirement_.min.x = 0;
requirement_.min.y = 0;
if (!children.empty()) {
children[0]->ComputeRequirement();
requirement_ = children[0]->requirement();
}
requirement_.flex.x = 0;
requirement_.flex.y = 0;
}
};
std::unique_ptr<Node> filler() {
return std::make_unique<Flex>();
}
@@ -34,4 +51,8 @@ std::unique_ptr<Node> flex(Element child) {
return std::make_unique<Flex>(std::move(child));
}
std::unique_ptr<Node> notflex(Element child) {
return std::make_unique<NotFlex>(std::move(child));
}
}; // namespace ftxui

View File

@@ -6,7 +6,7 @@ const wchar_t charset[] = L" ▗▐▖▄▟▌▙█";
class Graph : public Node {
public:
Graph(GraphFunction& graph_function) : graph_function_(graph_function) {}
Graph(GraphFunction graph_function) : graph_function_(graph_function) {}
~Graph() override {}
void ComputeRequirement() override {
@@ -35,10 +35,10 @@ class Graph : public Node {
}
private:
GraphFunction& graph_function_;
GraphFunction graph_function_;
};
std::unique_ptr<Node> graph(GraphFunction& graph_function) {
std::unique_ptr<Node> graph(GraphFunction graph_function) {
return std::make_unique<Graph>(graph_function);
}

View File

@@ -23,16 +23,34 @@ class Separator : public Node {
else
c = U'';
Pixel p;
p.character = c;
RenderWithPixel(screen, p);
}
void RenderWithPixel(Screen& screen, Pixel pixel) {
for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.at(x, y) = c;
screen.PixelAt(x, y) = pixel;
}
}
}
};
class SeparatorWithPixel : public Separator {
public:
SeparatorWithPixel(Pixel p) : p(p) {}
~SeparatorWithPixel() override {}
void Render(Screen& screen) override { RenderWithPixel(screen, p); }
Pixel p;
};
std::unique_ptr<Node> separator() {
return std::make_unique<Separator>();
}
std::unique_ptr<Node> separator(Pixel pixel) {
return std::make_unique<SeparatorWithPixel>(pixel);
}
}; // namespace ftxui