Add Event.

This commit is contained in:
Arthur Sonzogni 2018-10-18 22:58:38 +02:00
parent 1a4b2c98b2
commit f94b63fafb
25 changed files with 273 additions and 76 deletions

View File

@ -1,6 +1,7 @@
add_subdirectory(color) add_subdirectory(color)
add_subdirectory(frame) add_subdirectory(frame)
add_subdirectory(gauge) add_subdirectory(gauge)
add_subdirectory(input)
add_subdirectory(menu) add_subdirectory(menu)
add_subdirectory(menu2) add_subdirectory(menu2)
add_subdirectory(print_key_press) add_subdirectory(print_key_press)

View File

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

47
examples/input/main.cpp Normal file
View File

@ -0,0 +1,47 @@
#include <chrono>
#include <iostream>
#include <thread>
#include "ftxui/screen_interactive.hpp"
#include "ftxui/component/input.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),
input_1(delegate->NewChild()),
input_2(delegate->NewChild()),
input_3(delegate->NewChild()) {
Focus(&input_1);
}
std::function<void()> on_enter = []() {};
private:
Input input_1;
Input input_2;
Input input_3;
Element Render() override {
return
frame(
vbox(
hbox(text(L" input_1 : "), input_1.Render()),
hbox(text(L" input_2 : "), input_2.Render()),
hbox(text(L" input_3 : "), input_3.Render())
)
);
}
};
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

@ -15,26 +15,30 @@ class DrawKey : public ftxui::component::Component {
using namespace ftxui::dom; using namespace ftxui::dom;
Children children; Children children;
for (size_t i = std::max(0, (int)keys.size() - 10); i < keys.size(); ++i) { for (size_t i = std::max(0, (int)keys.size() - 10); i < keys.size(); ++i) {
std::string code = "";
for(size_t j = 0; j<5; ++j)
code += " " + std::to_string(keys[i].values[j]);
try { try {
std::string line = std::to_string(i) + " -> " + std::to_string(keys[i]) + std::string line = code + " -> " + std::to_string(keys[i].values[0]) + " (" +
" (" + char(keys[i]) + ")"; char(keys[i].values[0]) + ")";
children.push_back(text(to_wstring(line))); children.push_back(text(to_wstring(line)));
} catch (...) { } catch (...) {
std::string line = std::to_string(i) + " -> " + std::to_string(keys[i]) + std::string line =
" (undefined)"; code + " -> " + std::to_string(keys[i].values[0]) + " (undefined)";
children.push_back(text(to_wstring(line))); children.push_back(text(to_wstring(line)));
} }
} }
return vbox(std::move(children)); return vbox(std::move(children));
} }
bool Event(int key) override { bool OnEvent(ftxui::Event event) override {
keys.push_back(key); keys.push_back(event);
return true; return true;
} }
private: private:
std::vector<int> keys; std::vector<ftxui::Event> keys;
}; };
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -8,6 +8,7 @@
#include "ftxui/component/component_vertical.hpp" #include "ftxui/component/component_vertical.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/util/string.hpp"
using namespace ftxui;
using namespace ftxui::component; using namespace ftxui::component;
using namespace ftxui::dom; using namespace ftxui::dom;
@ -48,11 +49,11 @@ class MyComponent : ComponentVertical {
); );
} }
bool Event(int key) override { bool OnEvent(Event event) override {
if (ComponentVertical::Event(key)) if (ComponentVertical::OnEvent(event))
return true; return true;
if (key == 10) { if (event == Event::Return) {
on_enter(); on_enter();
return true; return true;
} }

View File

@ -6,6 +6,7 @@ add_library(ftxui
src/ftxui/component/component_direction.cpp src/ftxui/component/component_direction.cpp
src/ftxui/component/component_horizontal.cpp src/ftxui/component/component_horizontal.cpp
src/ftxui/component/component_vertical.cpp src/ftxui/component/component_vertical.cpp
src/ftxui/component/input.cpp
src/ftxui/component/menu.cpp src/ftxui/component/menu.cpp
src/ftxui/component/toggle.cpp src/ftxui/component/toggle.cpp
src/ftxui/dom/bold.cpp src/ftxui/dom/bold.cpp
@ -14,7 +15,6 @@ add_library(ftxui
src/ftxui/dom/dim.cpp src/ftxui/dom/dim.cpp
src/ftxui/dom/flex.cpp src/ftxui/dom/flex.cpp
src/ftxui/dom/frame.cpp src/ftxui/dom/frame.cpp
src/ftxui/dom/frame.cpp
src/ftxui/dom/gauge.cpp src/ftxui/dom/gauge.cpp
src/ftxui/dom/hbox.cpp src/ftxui/dom/hbox.cpp
src/ftxui/dom/inverted.cpp src/ftxui/dom/inverted.cpp
@ -24,6 +24,7 @@ add_library(ftxui
src/ftxui/dom/text.cpp src/ftxui/dom/text.cpp
src/ftxui/dom/underlined.cpp src/ftxui/dom/underlined.cpp
src/ftxui/dom/vbox.cpp src/ftxui/dom/vbox.cpp
src/ftxui/event.cpp
src/ftxui/screen.cpp src/ftxui/screen.cpp
src/ftxui/screen_interactive.cpp src/ftxui/screen_interactive.cpp
src/ftxui/terminal.cpp src/ftxui/terminal.cpp

View File

@ -1,34 +0,0 @@
#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

@ -1,8 +1,9 @@
#ifndef FTXUI_COMPONENT_COMPONENT_HPP #ifndef FTXUI_COMPONENT_COMPONENT_HPP
#define FTXUI_COMPONENT_COMPONENT_HPP #define FTXUI_COMPONENT_COMPONENT_HPP
#include "ftxui/dom/elements.hpp"
#include "ftxui/component/delegate.hpp" #include "ftxui/component/delegate.hpp"
#include "ftxui/dom/elements.hpp"
#include "ftxui/event.hpp"
namespace ftxui { namespace ftxui {
namespace component { namespace component {
@ -20,7 +21,7 @@ class Component {
virtual dom::Element Render(); virtual dom::Element Render();
// Handle an event. By default, it calls this function on each children. // Handle an event. By default, it calls this function on each children.
virtual bool Event(int key); virtual bool OnEvent(Event even);
// If this component contains children, this indicates which one is active. It // If this component contains children, this indicates which one is active. It
// can be none of them. // can be none of them.

View File

@ -10,12 +10,12 @@ namespace component {
class ComponentDirection : public Component { class ComponentDirection : public Component {
public: public:
ComponentDirection(Delegate* delegate); ComponentDirection(Delegate* delegate);
bool Event(int key) override; bool OnEvent(Event) override;
Component* GetActiveChild() override; Component* GetActiveChild() override;
protected: protected:
void Focus(Component* child); void Focus(Component* child);
virtual bool HandleDirection(int key) = 0; virtual bool HandleDirection(Event) = 0;
Component* active_child_; Component* active_child_;
}; };

View File

@ -10,8 +10,8 @@ namespace component {
// It assumes its children are put in the horizontal direction. // It assumes its children are put in the horizontal direction.
class ComponentHorizontal : public ComponentDirection { class ComponentHorizontal : public ComponentDirection {
public: public:
ComponentHorizontal(Delegate* delegate); ComponentHorizontal(Delegate*);
bool HandleDirection(int key) override; bool HandleDirection(Event) override;
}; };
} // namespace component } // namespace component

View File

@ -10,8 +10,8 @@ namespace component {
// It assumes its children are put in the vertical direction. // It assumes its children are put in the vertical direction.
class ComponentVertical : public ComponentDirection { class ComponentVertical : public ComponentDirection {
public: public:
ComponentVertical(Delegate* delegate); ComponentVertical(Delegate*);
bool HandleDirection(int key) override; bool HandleDirection(Event) override;
}; };
} // namespace component } // namespace component

View File

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

View File

@ -22,7 +22,7 @@ class Menu : public Component {
// Component implementation. // Component implementation.
dom::Element Render() override; dom::Element Render() override;
bool Event(int key) override; bool OnEvent(Event) override;
}; };
} // namespace component } // namespace component

View File

@ -22,7 +22,7 @@ class Toggle : public Component {
// Component implementation. // Component implementation.
dom::Element Render() override; dom::Element Render() override;
bool Event(int key) override; bool OnEvent(Event) override;
}; };
} // namespace component } // namespace component

View File

@ -0,0 +1,37 @@
#ifndef FTXUI_EVENT_H_
#define FTXUI_EVENT_H_
#include <vector>
#include <array>
namespace ftxui {
struct Event{
public:
// --- Character ---
static Event Character(char);
// --- 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;
bool operator==(const Event& other) { return values == other.values; }
// Internal representation.
std::array<char, 5> values = {0, 0, 0, 0, 0};
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_EVENT_H_ */

View File

@ -17,7 +17,7 @@ dom::Element Component::Render() {
return text(L"Not implemented component"); return text(L"Not implemented component");
} }
bool Component::Event(int key) { bool Component::OnEvent(Event event) {
return false; return false;
} }

View File

@ -6,17 +6,17 @@ namespace component {
ComponentDirection::ComponentDirection(Delegate* delegate) ComponentDirection::ComponentDirection(Delegate* delegate)
: Component(delegate), active_child_(nullptr) {} : Component(delegate), active_child_(nullptr) {}
bool ComponentDirection::Event(int key) { bool ComponentDirection::OnEvent(Event event) {
if (!Focused()) if (!Focused())
return false; return false;
if (!active_child_) if (!active_child_)
return false; return false;
if (active_child_->Event(key)) if (active_child_->OnEvent(event))
return true; return true;
return HandleDirection(key); return HandleDirection(event);
} }
Component* ComponentDirection::GetActiveChild() { Component* ComponentDirection::GetActiveChild() {

View File

@ -6,9 +6,9 @@ namespace component {
ComponentHorizontal::ComponentHorizontal(Delegate* delegate) ComponentHorizontal::ComponentHorizontal(Delegate* delegate)
: ComponentDirection(delegate) {} : ComponentDirection(delegate) {}
bool ComponentHorizontal::HandleDirection(int key) { bool ComponentHorizontal::HandleDirection(Event event) {
// Left pressed ? // Left pressed ?
if (key == 68 || key == 'h') { if (event == Event::ArrowLeft || event == Event::Character('h')) {
Component* previous_sibling = active_child_->PreviousSibling(); Component* previous_sibling = active_child_->PreviousSibling();
if (previous_sibling) { if (previous_sibling) {
active_child_ = previous_sibling; active_child_ = previous_sibling;
@ -17,7 +17,7 @@ bool ComponentHorizontal::HandleDirection(int key) {
} }
// Left pressed ? // Left pressed ?
if (key == 67 || key == 'l') { if (event == Event::ArrowRight || event == Event::Character('l')) {
Component* next_sibling = active_child_->NextSibling(); Component* next_sibling = active_child_->NextSibling();
if (next_sibling) { if (next_sibling) {
active_child_ = next_sibling; active_child_ = next_sibling;

View File

@ -6,9 +6,9 @@ namespace component {
ComponentVertical::ComponentVertical(Delegate* delegate) ComponentVertical::ComponentVertical(Delegate* delegate)
: ComponentDirection(delegate) {} : ComponentDirection(delegate) {}
bool ComponentVertical::HandleDirection(int key) { bool ComponentVertical::HandleDirection(Event event) {
// Up pressed ? // Up pressed ?
if (key == 65 || key == 'k') { if (event == Event::ArrowUp || event == Event::Character('k')) {
Component* previous_sibling = active_child_->PreviousSibling(); Component* previous_sibling = active_child_->PreviousSibling();
if (previous_sibling) { if (previous_sibling) {
active_child_ = previous_sibling; active_child_ = previous_sibling;
@ -17,7 +17,7 @@ bool ComponentVertical::HandleDirection(int key) {
} }
// Down pressed ? // Down pressed ?
if (key == 66 || key == 'j') { if (event == Event::ArrowDown || event == Event::Character('j')) {
Component* next_sibling = active_child_->NextSibling(); Component* next_sibling = active_child_->NextSibling();
if (next_sibling) { if (next_sibling) {
active_child_ = next_sibling; active_child_ = next_sibling;

View File

@ -0,0 +1,46 @@
#include "ftxui/component/input.hpp"
#include "ftxui/util/string.hpp"
namespace ftxui {
namespace component {
Input::Input(Delegate* delegate): Component(delegate) {}
Input::~Input() {}
// Component implementation.
dom::Element Input::Render() {
bool is_place_ho
std::wstring& displayed_text = content.size() ? content : placeholder;
using namespace dom;
if (Focused())
return flex(inverted(text(displayed_text)));
else
return flex(text(displayed_text));
}
bool Input::OnEvent(Event event) {
std::wstring c;
// Backspace
if (event == Event::Backspace) {
if (content.size() != 0)
content = content.substr(0, content.size()-1);
return true;
}
// Enter
if (event == Event::Return) {
return true;
}
constexpr char ESC = char(27);
if (event.values[0] != ESC) {
content += event.values[0];
return true;
}
return false;
}
} // namespace component
} // namespace ftxui

View File

@ -1,5 +1,6 @@
#include "ftxui/component/menu.hpp" #include "ftxui/component/menu.hpp"
#include <algorithm> #include <algorithm>
#include <iostream>
namespace ftxui { namespace ftxui {
namespace component { namespace component {
@ -24,14 +25,14 @@ dom::Element Menu::Render() {
return vbox(std::move(elements)); return vbox(std::move(elements));
} }
bool Menu::Event(int key) { bool Menu::OnEvent(Event event) {
if (!Focused()) if (!Focused())
return false; return false;
int new_selected = selected; int new_selected = selected;
if (key == 65 || key == 'k') if (event == Event::ArrowUp || event == Event::Character('k'))
new_selected--; new_selected--;
if (key == 66 || key == 'j') if (event == Event::ArrowDown || event == Event::Character('j'))
new_selected++; new_selected++;
new_selected = std::max(0, std::min(int(entries.size())-1, new_selected)); new_selected = std::max(0, std::min(int(entries.size())-1, new_selected));
@ -41,7 +42,7 @@ bool Menu::Event(int key) {
return true; return true;
} }
if (key == 10) { if (event == Event::Return) {
on_enter(); on_enter();
return true; return true;
} }

View File

@ -24,16 +24,15 @@ dom::Element Toggle::Render() {
return hbox(std::move(children)); return hbox(std::move(children));
} }
bool Toggle::Event(int key) { bool Toggle::OnEvent(Event event) {
if (activated) { if (activated) {
if (key == 67 || key == 'l') { if (event == Event::ArrowRight || event == Event::Character('l')) {
activated = false; activated = false;
on_change(); on_change();
return true; return true;
} }
} else { } else {
if (key == 68 || key == 'h') { if (event == Event::ArrowLeft || event == Event::Character('h')) {
activated = true; activated = true;
on_change(); on_change();
return true; return true;

37
ftxui/src/ftxui/event.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "ftxui/event.hpp"
namespace ftxui {
constexpr char ESC = char(27);
// --- Character ---
Event Event::Character(char c) {
return Event{c};
}
// --- Arrow ---
Event Event::ArrowLeft{ESC, '[', 'D'};
Event Event::ArrowRight{ESC, '[', 'C'};
Event Event::ArrowUp{ESC, '[', 'A'};
Event Event::ArrowDown{ESC, '[', 'B'};
// --- Other ---
Event Event::Backspace{char(127)};
Event Event::Delete{ESC, '[', '3', '~'};
Event Event::Escape{ESC};
Event Event::Return{char(10)};
Event Event::F1{ESC, '[', 'O', 'P'};
Event Event::F2{ESC, '[', 'O', 'Q'};
Event Event::F3{ESC, '[', 'O', 'R'};
Event Event::F4{ESC, '[', 'O', 'S'};
Event Event::F5{ESC, '[', '1', '5', '~'};
Event Event::F6{ESC, '[', '1', '7', '~'};
Event Event::F7{ESC, '[', '1', '8', '~'};
Event Event::F8{ESC, '[', '1', '9', '~'};
Event Event::F9{ESC, '[', '2', '0', '~'};
Event Event::F10{ESC, '[', '2', '1', '~'};
Event Event::F11{ESC, '[', '2', '1', '~'}; // Same as F10 ?
Event Event::F12{ESC, '[', '2', '4', '~'};
} // namespace ftxui

View File

@ -8,6 +8,20 @@
namespace ftxui { namespace ftxui {
namespace {
constexpr char ESC = char(27);
Event GetEvent() {
char v1 = char(getchar());
if (v1 != ESC)
return Event{v1};
char v2 = char(getchar());
char v3 = char(getchar());
return Event{v1,v2,v3};
};
};
class ScreenInteractive::Delegate : public component::Delegate { class ScreenInteractive::Delegate : public component::Delegate {
public: public:
Delegate() : root_(this) {} Delegate() : root_(this) {}
@ -29,7 +43,7 @@ class ScreenInteractive::Delegate : public component::Delegate {
return child; return child;
} }
void Event(int key) { component_->Event(key); } void OnEvent(Event event) { component_->OnEvent(event); }
std::vector<component::Delegate*> children() override { std::vector<component::Delegate*> children() override {
@ -77,8 +91,7 @@ void ScreenInteractive::Loop() {
Draw(); Draw();
while (!quit_) { while (!quit_) {
int key = getchar(); delegate_->OnEvent(GetEvent());
delegate_->Event(key);
Clear(); Clear();
Draw(); Draw();

View File

@ -23,6 +23,8 @@ Element bold(Element);
Element dim(Element); Element dim(Element);
Element inverted(Element); Element inverted(Element);
Element underlined(Element); Element underlined(Element);
Element color(Color,Element);
Element bgcolor(Element);
// --- Decorator --- // --- Decorator ---
Element hcenter(Element); Element hcenter(Element);
@ -139,3 +141,5 @@ Element bold(Element);
Element dim(Element); Element dim(Element);
Element inverted(Element); Element inverted(Element);
Element underlined(Element); Element underlined(Element);
Element color(Element);
Element bgcolor(Element);