12#include <initializer_list>
35#define DEFINE_CONSOLEV2_PROPERTIES
36#define WIN32_LEAN_AND_MEAN
42#error Must be compiled in UNICODE mode
45#include <sys/select.h>
51#if defined(__clang__) && defined(__APPLE__)
52#define quick_exit(a) exit(a)
61 screen->RequestAnimationFrame();
72 std::cout <<
'\0' << std::flush;
82 auto parser = TerminalInputParser(
out->Clone());
105 switch (
r.EventType) {
130#elif defined(__EMSCRIPTEN__)
131#include <emscripten.h>
136 auto parser = TerminalInputParser(std::move(
out));
172 auto parser = TerminalInputParser(std::move(
out));
181 std::array<char, buffer_size>
buffer;
183 for (
size_t i = 0;
i <
l; ++
i) {
256const std::string
CSI =
"\x1b[";
265 kMouseVt200Highlight = 1001,
267 kMouseBtnEventMouse = 1002,
268 kMouseAnyEvent = 1003,
271 kMouseSgrExtMode = 1006,
272 kMouseUrxvtMode = 1015,
273 kMouseSgrPixelsMode = 1016,
274 kAlternateScreen = 1049,
296std::string Set(
const std::vector<DECMode>&
parameters) {
307 return CSI + std::to_string(
int(
ps)) +
"n";
310class CapturedMouseImpl :
public CapturedMouseInterface {
312 explicit CapturedMouseImpl(std::function<
void(
void)>
callback)
315 CapturedMouseImpl(
const CapturedMouseImpl&) =
delete;
316 CapturedMouseImpl(CapturedMouseImpl&&) =
delete;
317 CapturedMouseImpl& operator=(
const CapturedMouseImpl&) =
delete;
318 CapturedMouseImpl& operator=(CapturedMouseImpl&&) =
delete;
321 std::function<
void(
void)> callback_;
326 const auto time_delta = std::chrono::milliseconds(15);
328 out->Send(AnimationTask());
335ScreenInteractive::ScreenInteractive(
int dimx,
339 : Screen(dimx, dimy),
360 Dimension::Fullscreen,
370 Dimension::TerminalOutput,
380 Dimension::FitComponent,
415 task_sender_->Send(std::move(
task));
428 if (animation_requested_) {
431 animation_requested_ =
true;
432 auto now = animation::Clock::now();
435 previous_animation_time_ =
now;
444 if (mouse_captured) {
447 mouse_captured =
true;
448 return std::make_unique<CapturedMouseImpl>(
449 [
this] { mouse_captured =
false; });
462bool ScreenInteractive::HasQuitted() {
467void ScreenInteractive::PreMain() {
472 suspended_screen_->ResetCursorPosition();
474 suspended_screen_->
dimx_ = 0;
475 suspended_screen_->
dimy_ = 0;
478 suspended_screen_->Uninstall();
485 previous_animation_time_ = animation::Clock::now();
489void ScreenInteractive::PostMain() {
491 ResetCursorPosition();
496 if (suspended_screen_) {
510 if (!use_alternative_screen_) {
511 std::cout << std::endl;
534void ScreenInteractive::Install() {
535 frame_valid_ =
false;
611 if (use_alternative_screen_) {
613 DECMode::kAlternateScreen,
618 std::cout <<
"\033[?25h";
619 std::cout <<
"\033[?1 q";
628 enable({DECMode::kMouseVt200});
629 enable({DECMode::kMouseAnyEvent});
630 enable({DECMode::kMouseUrxvtMode});
631 enable({DECMode::kMouseSgrExtMode});
639 task_sender_ = task_receiver_->MakeSender();
641 std::thread(&
EventListener, &quit_, task_receiver_->MakeSender());
642 animation_listener_ =
647void ScreenInteractive::Uninstall() {
649 event_listener_.join();
650 animation_listener_.join();
659 if (task_receiver_->Receive(&
task)) {
668 while (task_receiver_->ReceiveNonBlocking(&
task)) {
678 std::visit([&](
auto&&
arg) {
679 using T = std::decay_t<
decltype(
arg)>;
682 if constexpr (std::is_same_v<T, Event>) {
683 if (
arg.is_cursor_reporting()) {
684 cursor_x_ =
arg.cursor_x();
685 cursor_y_ =
arg.cursor_y();
689 if (
arg.is_mouse()) {
690 arg.mouse().x -= cursor_x_;
691 arg.mouse().y -= cursor_y_;
696 frame_valid_ =
false;
701 if constexpr (std::is_same_v<T, Closure>) {
707 if constexpr (std::is_same_v<T, AnimationTask>) {
708 if (!animation_requested_) {
712 animation_requested_ =
false;
715 previous_animation_time_ =
now;
719 frame_valid_ =
false;
738 switch (dimension_) {
739 case Dimension::Fixed:
743 case Dimension::TerminalOutput:
747 case Dimension::Fullscreen:
751 case Dimension::FitComponent:
758 ResetCursorPosition();
765 pixels_ = std::vector<std::vector<Pixel>>(
dimy, std::vector<Pixel>(
dimx));
773#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
782 if (!use_alternative_screen_ && (
i % 150 == 0)) {
788 if (!use_alternative_screen_ &&
789 (previous_frame_resized_ ||
i % 40 == 0)) {
793 previous_frame_resized_ =
resized;
802 set_cursor_position =
"\x1B[" + std::to_string(
dy) +
"A" +
803 "\x1B[" + std::to_string(
dx) +
"D";
804 reset_cursor_position =
"\x1B[" + std::to_string(
dy) +
"B" +
805 "\x1B[" + std::to_string(
dx) +
"C";
808 set_cursor_position +=
"\033[?25l";
810 set_cursor_position +=
"\033[?25h";
811 set_cursor_position +=
816 std::cout <<
ToString() << set_cursor_position;
823void ScreenInteractive::ResetCursorPosition() {
824 std::cout << reset_cursor_position;
825 reset_cursor_position =
"";
831 return [
this] {
Exit(); };
837 Post([
this] { ExitNow(); });
841void ScreenInteractive::ExitNow() {
843 task_sender_.reset();
847void ScreenInteractive::Signal(
int signal) {
857 ResetCursorPosition();
863 std::ignore = std::raise(
SIGTSTP);
bool HasQuitted()
Whether the loop has quitted.
static void Signal(ScreenInteractive &s, int signal)
static ScreenInteractive TerminalOutput()
void Exit()
Exit the main loop.
static ScreenInteractive FixedSize(int dimx, int dimy)
void PostEvent(Event event)
Add an event to the main loop. It will be executed later, after every other scheduled events.
void Post(Task task)
Add a task to the main loop. It will be executed later, after every other scheduled tasks.
static ScreenInteractive FitComponent()
static ScreenInteractive Fullscreen()
static ScreenInteractive * Active()
Return the currently active screen, or null if none.
CapturedMouse CaptureMouse()
Try to get the unique lock about behing able to capture the mouse.
void TrackMouse(bool enable=true)
Set whether mouse is tracked and events reported. called outside of the main loop....
void RequestAnimationFrame()
Add a task to draw the screen one more time, until all the animations are done.
Closure ExitLoopClosure()
Return a function to exit the main loop.
Closure WithRestoredIO(Closure)
Decorate a function. It executes the same way, but with the currently active screen terminal hooks te...
std::string ToString() const
std::string ResetPosition(bool clear=false) const
Return a string to be printed in order to reset the cursor position to the beginning of the screen.
void Clear()
Clear all the pixel from the screen.
std::vector< std::vector< Pixel > > pixels_
void SetFallbackSize(const Dimensions &fallbackSize)
Override terminal size in case auto-detection fails.
Dimensions Size()
Get the terminal size.
std::chrono::duration< float > Duration
std::chrono::time_point< Clock > TimePoint
void RequestAnimationFrame()
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< ComponentBase > Component
std::string to_string(const std::wstring &s)
Convert a UTF8 std::string into a std::wstring.
Element select(Element)
Set the child to be the one selected among its siblings.
Component Slider(SliderOption< T > options)
A slider in any direction.
std::variant< Event, Closure, AnimationTask > Task
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
std::function< void()> Closure
Represent an event. It can be key press event, a terminal resize, or more ...
static Event Special(std::string)
An custom event whose meaning is defined by the user of the library.