mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-17 00:18:11 +08:00
Add clang-tidy. (#368)
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath> // for sin, pow, sqrt, M_PI_2, M_PI, cos
|
||||
#include <cmath>
|
||||
#include <ratio> // for ratio
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/component/animation.hpp"
|
||||
|
||||
#include <ratio> // for ratio
|
||||
|
||||
namespace ftxui {
|
||||
namespace animation {
|
||||
namespace ftxui::animation {
|
||||
|
||||
namespace easing {
|
||||
|
||||
namespace {
|
||||
constexpr float kPi = 3.14159265358979323846F;
|
||||
constexpr float kPi2 = kPi / 2.F;
|
||||
} // namespace
|
||||
|
||||
// Easing function have been taken out of:
|
||||
// https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c
|
||||
//
|
||||
@@ -40,7 +44,7 @@ float QuadraticOut(float p) {
|
||||
// y = (1/2)((2x)^2) ; [0, 0.5)
|
||||
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
|
||||
float QuadraticInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 2 * p * p;
|
||||
} else {
|
||||
return (-2 * p * p) + (4 * p) - 1;
|
||||
@@ -62,11 +66,11 @@ float CubicOut(float p) {
|
||||
// y = (1/2)((2x)^3) ; [0, 0.5)
|
||||
// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
|
||||
float CubicInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 4 * p * p * p;
|
||||
} else {
|
||||
float f = ((2 * p) - 2);
|
||||
return 0.5 * f * f * f + 1;
|
||||
return 0.5F * f * f * f + 1; // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,11 +89,11 @@ float QuarticOut(float p) {
|
||||
// y = (1/2)((2x)^4) ; [0, 0.5)
|
||||
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
|
||||
float QuarticInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
return 8 * p * p * p * p;
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 8 * p * p * p * p; // NOLINT
|
||||
} else {
|
||||
float f = (p - 1);
|
||||
return -8 * f * f * f * f + 1;
|
||||
return -8 * f * f * f * f + 1; // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,119 +112,122 @@ float QuinticOut(float p) {
|
||||
// y = (1/2)((2x)^5) ; [0, 0.5)
|
||||
// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
|
||||
float QuinticInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
return 16 * p * p * p * p * p;
|
||||
} else {
|
||||
float f = ((2 * p) - 2);
|
||||
return 0.5 * f * f * f * f * f + 1;
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 16 * p * p * p * p * p; // NOLINT
|
||||
} else { // NOLINT
|
||||
float f = ((2 * p) - 2); // NOLINT
|
||||
return 0.5 * f * f * f * f * f + 1; // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
// Modeled after quarter-cycle of sine wave
|
||||
float SineIn(float p) {
|
||||
return sin((p - 1) * M_PI_2) + 1;
|
||||
return std::sin((p - 1) * kPi2) + 1;
|
||||
}
|
||||
|
||||
// Modeled after quarter-cycle of sine wave (different phase)
|
||||
float SineOut(float p) {
|
||||
return sin(p * M_PI_2);
|
||||
return std::sin(p * kPi2);
|
||||
}
|
||||
|
||||
// Modeled after half sine wave
|
||||
float SineInOut(float p) {
|
||||
return 0.5 * (1 - cos(p * M_PI));
|
||||
return 0.5F * (1 - std::cos(p * kPi)); // NOLINT
|
||||
}
|
||||
|
||||
// Modeled after shifted quadrant IV of unit circle
|
||||
float CircularIn(float p) {
|
||||
return 1 - sqrt(1 - (p * p));
|
||||
return 1 - std::sqrt(1 - (p * p));
|
||||
}
|
||||
|
||||
// Modeled after shifted quadrant II of unit circle
|
||||
float CircularOut(float p) {
|
||||
return sqrt((2 - p) * p);
|
||||
return std::sqrt((2 - p) * p);
|
||||
}
|
||||
|
||||
// Modeled after the piecewise circular function
|
||||
// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5)
|
||||
// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
|
||||
float CircularInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
return 0.5 * (1 - sqrt(1 - 4 * (p * p)));
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 0.5F * (1 - std::sqrt(1 - 4 * (p * p))); // NOLINT
|
||||
} else {
|
||||
return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1);
|
||||
return 0.5F * (std::sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
// Modeled after the exponential function y = 2^(10(x - 1))
|
||||
float ExponentialIn(float p) {
|
||||
return (p == 0.0) ? p : pow(2, 10 * (p - 1));
|
||||
return (p == 0.0) ? p : std::pow(2, 10 * (p - 1)); // NOLINT
|
||||
}
|
||||
|
||||
// Modeled after the exponential function y = -2^(-10x) + 1
|
||||
float ExponentialOut(float p) {
|
||||
return (p == 1.0) ? p : 1 - pow(2, -10 * p);
|
||||
return (p == 1.0) ? p : 1 - std::pow(2, -10 * p); // NOLINT
|
||||
}
|
||||
|
||||
// Modeled after the piecewise exponential
|
||||
// y = (1/2)2^(10(2x - 1)) ; [0,0.5)
|
||||
// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
|
||||
float ExponentialInOut(float p) {
|
||||
if (p == 0.0 || p == 1.0)
|
||||
if (p == 0.0 || p == 1.F) {
|
||||
return p;
|
||||
}
|
||||
|
||||
if (p < 0.5) {
|
||||
return 0.5 * pow(2, (20 * p) - 10);
|
||||
} else {
|
||||
return -0.5 * pow(2, (-20 * p) + 10) + 1;
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 0.5 * std::pow(2, (20 * p) - 10); // NOLINT
|
||||
} else { // NOLINT
|
||||
return -0.5 * std::pow(2, (-20 * p) + 10) + 1; // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
|
||||
float ElasticIn(float p) {
|
||||
return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1));
|
||||
return std::sin(13.F * kPi2 * p) * std::pow(2.F, 10.F * (p - 1)); // NOLINT
|
||||
}
|
||||
|
||||
// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) +
|
||||
// 1
|
||||
float ElasticOut(float p) {
|
||||
return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1;
|
||||
return std::sin(-13.F * kPi2 * (p + 1)) * std::pow(2.F, -10.F * p) +
|
||||
1; // NOLINT
|
||||
}
|
||||
|
||||
// Modeled after the piecewise exponentially-damped sine wave:
|
||||
// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5)
|
||||
// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
|
||||
float ElasticInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
return 0.5 * sin(13 * M_PI_2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1));
|
||||
} else {
|
||||
return 0.5 *
|
||||
(sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) +
|
||||
2);
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 0.5 * std::sin(13.F * kPi2 * (2 * p)) * // NOLINT
|
||||
std::pow(2, 10 * ((2 * p) - 1)); // NOLINT
|
||||
} else { // NOLINT
|
||||
return 0.5 * (std::sin(-13.F * kPi2 * ((2 * p - 1) + 1)) * // NOLINT
|
||||
std::pow(2, -10 * (2 * p - 1)) + // NOLINT
|
||||
2); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
// Modeled after the overshooting cubic y = x^3-x*sin(x*pi)
|
||||
float BackIn(float p) {
|
||||
return p * p * p - p * sin(p * M_PI);
|
||||
return p * p * p - p * std::sin(p * kPi);
|
||||
}
|
||||
|
||||
// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
|
||||
float BackOut(float p) {
|
||||
float f = (1 - p);
|
||||
return 1 - (f * f * f - f * sin(f * M_PI));
|
||||
return 1 - (f * f * f - f * std::sin(f * kPi));
|
||||
}
|
||||
|
||||
// Modeled after the piecewise overshooting cubic function:
|
||||
// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5)
|
||||
// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
|
||||
float BackInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
if (p < 0.5F) { // NOLINT
|
||||
float f = 2 * p;
|
||||
return 0.5 * (f * f * f - f * sin(f * M_PI));
|
||||
return 0.5F * (f * f * f - f * std::sin(f * kPi)); // NOLINT
|
||||
} else {
|
||||
float f = (1 - (2 * p - 1));
|
||||
return 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5;
|
||||
float f = (1 - (2 * p - 1)); // NOLINT
|
||||
return 0.5F * (1 - (f * f * f - f * std::sin(f * kPi))) + 0.5; // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,22 +236,23 @@ float BounceIn(float p) {
|
||||
}
|
||||
|
||||
float BounceOut(float p) {
|
||||
if (p < 4 / 11.0) {
|
||||
return (121 * p * p) / 16.0;
|
||||
} else if (p < 8 / 11.0) {
|
||||
return (363 / 40.0 * p * p) - (99 / 10.0 * p) + 17 / 5.0;
|
||||
} else if (p < 9 / 10.0) {
|
||||
return (4356 / 361.0 * p * p) - (35442 / 1805.0 * p) + 16061 / 1805.0;
|
||||
} else {
|
||||
return (54 / 5.0 * p * p) - (513 / 25.0 * p) + 268 / 25.0;
|
||||
if (p < 4 / 11.0) { // NOLINT
|
||||
return (121 * p * p) / 16.0; // NOLINT
|
||||
} else if (p < 8 / 11.0) { // NOLINT
|
||||
return (363 / 40.0 * p * p) - (99 / 10.0 * p) + 17 / 5.0; // NOLINT
|
||||
} else if (p < 9 / 10.0) { // NOLINT
|
||||
return (4356 / 361.0 * p * p) - (35442 / 1805.0 * p) + // NOLINT
|
||||
16061 / 1805.0; // NOLINT
|
||||
} else { // NOLINT
|
||||
return (54 / 5.0 * p * p) - (513 / 25.0 * p) + 268 / 25.0; // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
float BounceInOut(float p) {
|
||||
if (p < 0.5) {
|
||||
return 0.5 * BounceIn(p * 2);
|
||||
} else {
|
||||
return 0.5 * BounceOut(p * 2 - 1) + 0.5;
|
||||
float BounceInOut(float p) { // NOLINT
|
||||
if (p < 0.5F) { // NOLINT
|
||||
return 0.5F * BounceIn(p * 2); // NOLINT
|
||||
} else { // NOLINT
|
||||
return 0.5F * BounceOut(p * 2 - 1) + 0.5F; // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +267,7 @@ Animator::Animator(float* from,
|
||||
from_(*from),
|
||||
to_(to),
|
||||
duration_(duration),
|
||||
easing_function_(easing_function),
|
||||
easing_function_(std::move(easing_function)),
|
||||
current_(-delay) {
|
||||
RequestAnimationFrame();
|
||||
}
|
||||
@@ -275,11 +283,11 @@ void Animator::OnAnimation(Params& params) {
|
||||
if (current_ <= Duration()) {
|
||||
*value_ = from_;
|
||||
} else {
|
||||
*value_ = from_ + (to_ - from_) * easing_function_(current_ / duration_);
|
||||
*value_ = from_ +
|
||||
(to_ - from_) * easing_function_(current_ / duration_); // NOLINT
|
||||
}
|
||||
|
||||
RequestAnimationFrame();
|
||||
}
|
||||
|
||||
} // namespace animation
|
||||
} // namespace ftxui
|
||||
} // namespace ftxui::animation
|
||||
|
@@ -1,17 +1,16 @@
|
||||
#include <functional> // for function
|
||||
#include <memory> // for shared_ptr
|
||||
#include <string> // for string
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/component/animation.hpp" // for Animator, Params (ptr only)
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
|
||||
#include "ftxui/component/component.hpp" // for Make, Button
|
||||
#include "ftxui/component/component_base.hpp" // for ComponentBase
|
||||
#include "ftxui/component/component_options.hpp" // for ButtonOption, AnimatedColorOption, AnimatedColorsOption
|
||||
#include "ftxui/component/component_options.hpp" // for ButtonOption, AnimatedColorOption, AnimatedColorsOption, EntryState
|
||||
#include "ftxui/component/event.hpp" // for Event, Event::Return
|
||||
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed
|
||||
#include "ftxui/component/screen_interactive.hpp" // for Component
|
||||
#include "ftxui/dom/elements.hpp" // for operator|, Decorator, Element, bgcolor, color, operator|=, reflect, text, border, inverted, nothing
|
||||
#include "ftxui/dom/elements.hpp" // for operator|, Decorator, Element, operator|=, bgcolor, color, reflect, text, bold, border, inverted, nothing
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
#include "ftxui/screen/color.hpp" // for Color
|
||||
#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef
|
||||
@@ -20,12 +19,14 @@ namespace ftxui {
|
||||
|
||||
namespace {
|
||||
|
||||
Element DefaultTransform(EntryState params) {
|
||||
Element DefaultTransform(EntryState params) { // NOLINT
|
||||
auto element = text(params.label) | border;
|
||||
if (params.active)
|
||||
if (params.active) {
|
||||
element |= bold;
|
||||
if (params.focused)
|
||||
}
|
||||
if (params.focused) {
|
||||
element |= inverted;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -62,13 +63,16 @@ Component Button(ConstStringRef label,
|
||||
Impl(ConstStringRef label,
|
||||
std::function<void()> on_click,
|
||||
Ref<ButtonOption> option)
|
||||
: label_(label), on_click_(on_click), option_(std::move(option)) {}
|
||||
: label_(std::move(label)),
|
||||
on_click_(std::move(on_click)),
|
||||
option_(std::move(option)) {}
|
||||
|
||||
// Component implementation:
|
||||
Element Render() override {
|
||||
float target = Focused() ? 1.0 : 0.f;
|
||||
if (target != animator_background_.to())
|
||||
float target = Focused() ? 1.F : 0.F; // NOLINT
|
||||
if (target != animator_background_.to()) {
|
||||
SetAnimationTarget(target);
|
||||
}
|
||||
|
||||
EntryState state = {
|
||||
*label_,
|
||||
@@ -122,14 +126,15 @@ Component Button(ConstStringRef label,
|
||||
|
||||
void OnClick() {
|
||||
on_click_();
|
||||
animation_background_ = 0.5f;
|
||||
animation_foreground_ = 0.5f;
|
||||
SetAnimationTarget(1.f);
|
||||
animation_background_ = 0.5F; // NOLINT
|
||||
animation_foreground_ = 0.5F; // NOLINT
|
||||
SetAnimationTarget(1.F); // NOLINT
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) override {
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
if (event == Event::Return) {
|
||||
OnClick();
|
||||
@@ -142,8 +147,9 @@ Component Button(ConstStringRef label,
|
||||
mouse_hover_ =
|
||||
box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event);
|
||||
|
||||
if (!mouse_hover_)
|
||||
if (!mouse_hover_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TakeFocus();
|
||||
|
||||
@@ -172,7 +178,7 @@ Component Button(ConstStringRef label,
|
||||
animation::Animator(&animation_foreground_);
|
||||
};
|
||||
|
||||
return Make<Impl>(label, std::move(on_click), std::move(option));
|
||||
return Make<Impl>(std::move(label), std::move(on_click), std::move(option));
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -11,15 +11,16 @@ namespace ftxui {
|
||||
class CatchEventBase : public ComponentBase {
|
||||
public:
|
||||
// Constructor.
|
||||
CatchEventBase(std::function<bool(Event)> on_event)
|
||||
explicit CatchEventBase(std::function<bool(Event)> on_event)
|
||||
: on_event_(std::move(on_event)) {}
|
||||
|
||||
// Component implementation.
|
||||
bool OnEvent(Event event) override {
|
||||
if (on_event_(event))
|
||||
if (on_event_(event)) {
|
||||
return true;
|
||||
else
|
||||
} else {
|
||||
return ComponentBase::OnEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -76,8 +77,8 @@ Component CatchEvent(Component child,
|
||||
/// ```
|
||||
ComponentDecorator CatchEvent(std::function<bool(Event)> on_event) {
|
||||
return [on_event = std::move(on_event)](Component child) {
|
||||
return CatchEvent(child, [on_event = std::move(on_event)](Event event) {
|
||||
return on_event(event);
|
||||
return CatchEvent(std::move(child), [on_event = on_event](Event event) {
|
||||
return on_event(std::move(event));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ namespace {
|
||||
class CheckboxBase : public ComponentBase {
|
||||
public:
|
||||
CheckboxBase(ConstStringRef label, bool* state, Ref<CheckboxOption> option)
|
||||
: label_(label), state_(state), option_(std::move(option)) {}
|
||||
: label_(std::move(label)), state_(state), option_(std::move(option)) {}
|
||||
|
||||
private:
|
||||
// Component implementation.
|
||||
@@ -32,18 +32,20 @@ class CheckboxBase : public ComponentBase {
|
||||
is_active,
|
||||
is_focused || hovered_,
|
||||
};
|
||||
auto element = (option_->transform
|
||||
? option_->transform
|
||||
: CheckboxOption::Simple().transform)(std::move(state));
|
||||
auto element =
|
||||
(option_->transform ? option_->transform
|
||||
: CheckboxOption::Simple().transform)(state);
|
||||
return element | focus_management | reflect(box_);
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) override {
|
||||
if (!CaptureMouse(event))
|
||||
if (!CaptureMouse(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
hovered_ = false;
|
||||
if (event == Event::Character(' ') || event == Event::Return) {
|
||||
@@ -58,11 +60,13 @@ class CheckboxBase : public ComponentBase {
|
||||
bool OnMouseEvent(Event event) {
|
||||
hovered_ = box_.Contain(event.mouse().x, event.mouse().y);
|
||||
|
||||
if (!CaptureMouse(event))
|
||||
if (!CaptureMouse(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hovered_)
|
||||
if (!hovered_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Pressed) {
|
||||
@@ -109,7 +113,7 @@ class CheckboxBase : public ComponentBase {
|
||||
Component Checkbox(ConstStringRef label,
|
||||
bool* checked,
|
||||
Ref<CheckboxOption> option) {
|
||||
return Make<CheckboxBase>(label, checked, std::move(option));
|
||||
return Make<CheckboxBase>(std::move(label), checked, std::move(option));
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -1,10 +1,12 @@
|
||||
#include <string> // for string
|
||||
#include <utility> // for move
|
||||
#include <functional> // for function
|
||||
#include <memory> // for shared_ptr, allocator
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/component/component.hpp" // for Checkbox, Maybe, Make, Vertical, Collapsible
|
||||
#include "ftxui/component/component_base.hpp" // for Component, ComponentBase
|
||||
#include "ftxui/component/component_options.hpp" // for CheckboxOption
|
||||
#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef
|
||||
#include "ftxui/component/component_options.hpp" // for CheckboxOption, EntryState
|
||||
#include "ftxui/dom/elements.hpp" // for operator|=, text, hbox, Element, bold, inverted
|
||||
#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
@@ -28,27 +30,28 @@ namespace ftxui {
|
||||
Component Collapsible(ConstStringRef label, Component child, Ref<bool> show) {
|
||||
class Impl : public ComponentBase {
|
||||
public:
|
||||
Impl(ConstStringRef label, Component child, Ref<bool> show)
|
||||
: show_(std::move(show)) {
|
||||
Impl(ConstStringRef label, Component child, Ref<bool> show) : show_(show) {
|
||||
CheckboxOption opt;
|
||||
opt.transform = [](EntryState s) {
|
||||
auto prefix = text(s.state ? "▼ " : "▶ ");
|
||||
opt.transform = [](EntryState s) { // NOLINT
|
||||
auto prefix = text(s.state ? "▼ " : "▶ "); // NOLINT
|
||||
auto t = text(s.label);
|
||||
if (s.active)
|
||||
if (s.active) {
|
||||
t |= bold;
|
||||
if (s.focused)
|
||||
}
|
||||
if (s.focused) {
|
||||
t |= inverted;
|
||||
}
|
||||
return hbox({prefix, t});
|
||||
};
|
||||
Add(Container::Vertical({
|
||||
Checkbox(label, show_.operator->(), opt),
|
||||
Checkbox(std::move(label), show_.operator->(), opt),
|
||||
Maybe(std::move(child), show_.operator->()),
|
||||
}));
|
||||
}
|
||||
Ref<bool> show_;
|
||||
};
|
||||
|
||||
return Make<Impl>(label, std::move(child), std::move(show));
|
||||
return Make<Impl>(std::move(label), std::move(child), show);
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include <stddef.h> // for size_t
|
||||
#include <algorithm> // for find_if
|
||||
#include <cassert> // for assert
|
||||
#include <cstddef> // for size_t
|
||||
#include <iterator> // for begin, end
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector, __alloc_traits<>::value_type
|
||||
@@ -37,7 +37,7 @@ ComponentBase* ComponentBase::Parent() const {
|
||||
/// @brief Access the child at index `i`.
|
||||
/// @ingroup component
|
||||
Component& ComponentBase::ChildAt(size_t i) {
|
||||
assert(i < ChildCount());
|
||||
assert(i < ChildCount()); // NOLINT
|
||||
return children_[i];
|
||||
}
|
||||
|
||||
@@ -61,8 +61,9 @@ void ComponentBase::Add(Component child) {
|
||||
/// @see Parent
|
||||
/// @ingroup component
|
||||
void ComponentBase::Detach() {
|
||||
if (!parent_)
|
||||
if (parent_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto it = std::find_if(std::begin(parent_->children_), //
|
||||
std::end(parent_->children_), //
|
||||
[this](const Component& that) { //
|
||||
@@ -76,8 +77,9 @@ void ComponentBase::Detach() {
|
||||
/// @brief Remove all children.
|
||||
/// @ingroup component
|
||||
void ComponentBase::DetachAllChildren() {
|
||||
while (!children_.empty())
|
||||
while (!children_.empty()) {
|
||||
children_[0]->Detach();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Draw the component.
|
||||
@@ -85,8 +87,9 @@ void ComponentBase::DetachAllChildren() {
|
||||
/// ftxui::ComponentBase.
|
||||
/// @ingroup component
|
||||
Element ComponentBase::Render() {
|
||||
if (children_.size() == 1)
|
||||
if (children_.size() == 1) {
|
||||
return children_.front()->Render();
|
||||
}
|
||||
|
||||
return text("Not implemented component");
|
||||
}
|
||||
@@ -97,10 +100,11 @@ Element ComponentBase::Render() {
|
||||
/// The default implementation called OnEvent on every child until one return
|
||||
/// true. If none returns true, return false.
|
||||
/// @ingroup component
|
||||
bool ComponentBase::OnEvent(Event event) {
|
||||
for (Component& child : children_) {
|
||||
if (child->OnEvent(event))
|
||||
bool ComponentBase::OnEvent(Event event) { // NOLINT
|
||||
for (Component& child : children_) { // NOLINT
|
||||
if (child->OnEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -110,8 +114,9 @@ bool ComponentBase::OnEvent(Event event) {
|
||||
/// The default implementation dispatch the event to every child.
|
||||
/// @ingroup component
|
||||
void ComponentBase::OnAnimation(animation::Params& params) {
|
||||
for (Component& child : children_)
|
||||
for (Component& child : children_) {
|
||||
child->OnAnimation(params);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Return the currently Active child.
|
||||
@@ -119,8 +124,9 @@ void ComponentBase::OnAnimation(animation::Params& params) {
|
||||
/// @ingroup component
|
||||
Component ComponentBase::ActiveChild() {
|
||||
for (auto& child : children_) {
|
||||
if (child->Focusable())
|
||||
if (child->Focusable()) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -130,9 +136,10 @@ Component ComponentBase::ActiveChild() {
|
||||
/// keyboard.
|
||||
/// @ingroup component
|
||||
bool ComponentBase::Focusable() const {
|
||||
for (const Component& child : children_) {
|
||||
if (child->Focusable())
|
||||
for (const Component& child : children_) { // NOLINT
|
||||
if (child->Focusable()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -140,7 +147,7 @@ bool ComponentBase::Focusable() const {
|
||||
/// @brief Returns if the element if the currently active child of its parent.
|
||||
/// @ingroup component
|
||||
bool ComponentBase::Active() const {
|
||||
return !parent_ || parent_->ActiveChild().get() == this;
|
||||
return parent_ == nullptr || parent_->ActiveChild().get() == this;
|
||||
}
|
||||
|
||||
/// @brief Returns if the elements if focused by the user.
|
||||
@@ -149,7 +156,7 @@ bool ComponentBase::Active() const {
|
||||
/// Focusable().
|
||||
/// @ingroup component
|
||||
bool ComponentBase::Focused() const {
|
||||
auto current = this;
|
||||
const auto* current = this;
|
||||
while (current && current->Active()) {
|
||||
current = current->parent_;
|
||||
}
|
||||
@@ -159,12 +166,12 @@ bool ComponentBase::Focused() const {
|
||||
/// @brief Make the |child| to be the "active" one.
|
||||
/// @param child the child to become active.
|
||||
/// @ingroup component
|
||||
void ComponentBase::SetActiveChild(ComponentBase*) {}
|
||||
void ComponentBase::SetActiveChild(ComponentBase* /*child*/) {}
|
||||
|
||||
/// @brief Make the |child| to be the "active" one.
|
||||
/// @param child the child to become active.
|
||||
/// @ingroup component
|
||||
void ComponentBase::SetActiveChild(Component child) {
|
||||
void ComponentBase::SetActiveChild(Component child) { // NOLINT
|
||||
SetActiveChild(child.get());
|
||||
}
|
||||
|
||||
@@ -182,9 +189,10 @@ void ComponentBase::TakeFocus() {
|
||||
/// them. It represents a component taking priority over others.
|
||||
/// @param event
|
||||
/// @ingroup component
|
||||
CapturedMouse ComponentBase::CaptureMouse(const Event& event) {
|
||||
if (event.screen_)
|
||||
CapturedMouse ComponentBase::CaptureMouse(const Event& event) { // NOLINT
|
||||
if (event.screen_) {
|
||||
return event.screen_->CaptureMouse();
|
||||
}
|
||||
return std::make_unique<CaptureMouseImpl>();
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,10 @@
|
||||
#include "ftxui/component/component_options.hpp"
|
||||
|
||||
#include <memory> // for allocator, shared_ptr
|
||||
#include <memory> // for shared_ptr
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/component/animation.hpp" // for Function, Duration
|
||||
#include "ftxui/dom/elements.hpp" // for Element, operator|, text, bold, dim, inverted, automerge
|
||||
#include "ftxui/dom/elements.hpp" // for operator|=, text, Element, bold, inverted, operator|, dim, hbox, automerge, borderEmpty, borderLight
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
@@ -15,13 +16,13 @@ void AnimatedColorOption::Set(Color a_inactive,
|
||||
inactive = a_inactive;
|
||||
active = a_active;
|
||||
duration = a_duration;
|
||||
function = a_function;
|
||||
function = std::move(a_function);
|
||||
}
|
||||
|
||||
void UnderlineOption::SetAnimation(animation::Duration d,
|
||||
animation::easing::Function f) {
|
||||
SetAnimationDuration(d);
|
||||
SetAnimationFunction(f);
|
||||
SetAnimationFunction(std::move(f));
|
||||
}
|
||||
|
||||
void UnderlineOption::SetAnimationDuration(animation::Duration d) {
|
||||
@@ -31,28 +32,31 @@ void UnderlineOption::SetAnimationDuration(animation::Duration d) {
|
||||
|
||||
void UnderlineOption::SetAnimationFunction(animation::easing::Function f) {
|
||||
leader_function = f;
|
||||
follower_function = f;
|
||||
follower_function = std::move(f);
|
||||
}
|
||||
|
||||
void UnderlineOption::SetAnimationFunction(
|
||||
animation::easing::Function f_leader,
|
||||
animation::easing::Function f_follower) {
|
||||
leader_function = f_leader;
|
||||
follower_function = f_follower;
|
||||
leader_function = std::move(f_leader);
|
||||
follower_function = std::move(f_follower);
|
||||
}
|
||||
|
||||
// static
|
||||
MenuOption MenuOption::Horizontal() {
|
||||
MenuOption option;
|
||||
option.direction = Direction::Right;
|
||||
option.entries.transform = [](EntryState state) {
|
||||
option.entries.transform = [](const EntryState& state) {
|
||||
Element e = text(state.label);
|
||||
if (state.focused)
|
||||
if (state.focused) {
|
||||
e |= inverted;
|
||||
if (state.active)
|
||||
}
|
||||
if (state.active) {
|
||||
e |= bold;
|
||||
if (!state.focused && !state.active)
|
||||
}
|
||||
if (!state.focused && !state.active) {
|
||||
e |= dim;
|
||||
}
|
||||
return e;
|
||||
};
|
||||
option.elements_infix = [] { return text(" "); };
|
||||
@@ -70,19 +74,17 @@ MenuOption MenuOption::HorizontalAnimated() {
|
||||
// static
|
||||
MenuOption MenuOption::Vertical() {
|
||||
MenuOption option;
|
||||
option.entries.transform = [](EntryState state) {
|
||||
if (state.active)
|
||||
state.label = "> " + state.label;
|
||||
else
|
||||
state.label = " " + state.label;
|
||||
|
||||
Element e = text(state.label);
|
||||
if (state.focused)
|
||||
option.entries.transform = [](const EntryState& state) {
|
||||
Element e = text((state.active ? "> " : " ") + state.label); // NOLINT
|
||||
if (state.focused) {
|
||||
e |= inverted;
|
||||
if (state.active)
|
||||
}
|
||||
if (state.active) {
|
||||
e |= bold;
|
||||
if (!state.focused && !state.active)
|
||||
}
|
||||
if (!state.focused && !state.active) {
|
||||
e |= dim;
|
||||
}
|
||||
return e;
|
||||
};
|
||||
return option;
|
||||
@@ -91,14 +93,17 @@ MenuOption MenuOption::Vertical() {
|
||||
// static
|
||||
MenuOption MenuOption::VerticalAnimated() {
|
||||
auto option = MenuOption::Vertical();
|
||||
option.entries.transform = [](EntryState state) {
|
||||
option.entries.transform = [](const EntryState& state) {
|
||||
Element e = text(state.label);
|
||||
if (state.focused)
|
||||
if (state.focused) {
|
||||
e |= inverted;
|
||||
if (state.active)
|
||||
}
|
||||
if (state.active) {
|
||||
e |= bold;
|
||||
if (!state.focused && !state.active)
|
||||
}
|
||||
if (!state.focused && !state.active) {
|
||||
e |= dim;
|
||||
}
|
||||
return e;
|
||||
};
|
||||
option.underline.enabled = true;
|
||||
@@ -116,10 +121,10 @@ MenuOption MenuOption::Toggle() {
|
||||
// static
|
||||
ButtonOption ButtonOption::Ascii() {
|
||||
ButtonOption option;
|
||||
option.transform = [](EntryState s) {
|
||||
s.label = s.focused ? "[" + s.label + "]" //
|
||||
: " " + s.label + " ";
|
||||
return text(s.label);
|
||||
option.transform = [](const EntryState& s) {
|
||||
std::string label = s.focused ? "[" + s.label + "]" //
|
||||
: " " + s.label + " ";
|
||||
return text(label);
|
||||
};
|
||||
return option;
|
||||
}
|
||||
@@ -128,10 +133,11 @@ ButtonOption ButtonOption::Ascii() {
|
||||
// static
|
||||
ButtonOption ButtonOption::Simple() {
|
||||
ButtonOption option;
|
||||
option.transform = [](EntryState s) {
|
||||
option.transform = [](const EntryState& s) {
|
||||
auto element = text(s.label) | borderLight;
|
||||
if (s.focused)
|
||||
if (s.focused) {
|
||||
element |= inverted;
|
||||
}
|
||||
return element;
|
||||
};
|
||||
return option;
|
||||
@@ -147,10 +153,11 @@ ButtonOption ButtonOption::Animated() {
|
||||
/// @brief Create a ButtonOption, using animated colors.
|
||||
// static
|
||||
ButtonOption ButtonOption::Animated(Color color) {
|
||||
return ButtonOption::Animated(Color::Interpolate(0.85f, color, Color::Black),
|
||||
Color::Interpolate(0.10f, color, Color::White),
|
||||
Color::Interpolate(0.10f, color, Color::Black),
|
||||
Color::Interpolate(0.85f, color, Color::White));
|
||||
return ButtonOption::Animated(
|
||||
Color::Interpolate(0.85F, color, Color::Black), // NOLINT
|
||||
Color::Interpolate(0.10F, color, Color::White), // NOLINT
|
||||
Color::Interpolate(0.10F, color, Color::Black), // NOLINT
|
||||
Color::Interpolate(0.85F, color, Color::White)); // NOLINT
|
||||
}
|
||||
|
||||
/// @brief Create a ButtonOption, using animated colors.
|
||||
@@ -163,17 +170,18 @@ ButtonOption ButtonOption::Animated(Color background, Color foreground) {
|
||||
// static
|
||||
ButtonOption ButtonOption::Animated(Color background,
|
||||
Color foreground,
|
||||
Color background_focused,
|
||||
Color foreground_focused) {
|
||||
Color background_active,
|
||||
Color foreground_active) {
|
||||
ButtonOption option;
|
||||
option.transform = [](EntryState s) {
|
||||
option.transform = [](const EntryState& s) {
|
||||
auto element = text(s.label) | borderEmpty;
|
||||
if (s.focused)
|
||||
if (s.focused) {
|
||||
element |= bold;
|
||||
}
|
||||
return element;
|
||||
};
|
||||
option.animated_colors.foreground.Set(foreground, foreground_focused);
|
||||
option.animated_colors.background.Set(background, background_focused);
|
||||
option.animated_colors.foreground.Set(foreground, foreground_active);
|
||||
option.animated_colors.background.Set(background, background_active);
|
||||
return option;
|
||||
}
|
||||
|
||||
@@ -181,19 +189,21 @@ ButtonOption ButtonOption::Animated(Color background,
|
||||
// static
|
||||
CheckboxOption CheckboxOption::Simple() {
|
||||
auto option = CheckboxOption();
|
||||
option.transform = [](EntryState s) {
|
||||
option.transform = [](const EntryState& s) {
|
||||
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
|
||||
// Microsoft terminal do not use fonts able to render properly the default
|
||||
// radiobox glyph.
|
||||
auto prefix = text(s.state ? "[X] " : "[ ] ");
|
||||
auto prefix = text(s.state ? "[X] " : "[ ] "); // NOLINT
|
||||
#else
|
||||
auto prefix = text(s.state ? "▣ " : "☐ ");
|
||||
auto prefix = text(s.state ? "▣ " : "☐ "); // NOLINT
|
||||
#endif
|
||||
auto t = text(s.label);
|
||||
if (s.active)
|
||||
if (s.active) {
|
||||
t |= bold;
|
||||
if (s.focused)
|
||||
}
|
||||
if (s.focused) {
|
||||
t |= inverted;
|
||||
}
|
||||
return hbox({prefix, t});
|
||||
};
|
||||
return option;
|
||||
@@ -203,19 +213,21 @@ CheckboxOption CheckboxOption::Simple() {
|
||||
// static
|
||||
RadioboxOption RadioboxOption::Simple() {
|
||||
auto option = RadioboxOption();
|
||||
option.transform = [](EntryState s) {
|
||||
option.transform = [](const EntryState& s) {
|
||||
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
|
||||
// Microsoft terminal do not use fonts able to render properly the default
|
||||
// radiobox glyph.
|
||||
auto prefix = text(s.state ? "(*) " : "( ) ");
|
||||
auto prefix = text(s.state ? "(*) " : "( ) "); // NOLINT
|
||||
#else
|
||||
auto prefix = text(s.state ? "◉ " : "○ ");
|
||||
auto prefix = text(s.state ? "◉ " : "○ "); // NOLINT
|
||||
#endif
|
||||
auto t = text(s.label);
|
||||
if (s.active)
|
||||
if (s.active) {
|
||||
t |= bold;
|
||||
if (s.focused)
|
||||
}
|
||||
if (s.focused) {
|
||||
t |= inverted;
|
||||
}
|
||||
return hbox({prefix, t});
|
||||
};
|
||||
return option;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include <stddef.h> // for size_t
|
||||
#include <algorithm> // for max, min
|
||||
#include <cstddef> // for size_t
|
||||
#include <memory> // for make_shared, __shared_ptr_access, allocator, shared_ptr, allocator_traits<>::value_type
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector, __alloc_traits<>::value_type
|
||||
@@ -17,27 +17,32 @@ class ContainerBase : public ComponentBase {
|
||||
public:
|
||||
ContainerBase(Components children, int* selector)
|
||||
: selector_(selector ? selector : &selected_) {
|
||||
for (Component& child : children)
|
||||
for (Component& child : children) {
|
||||
Add(std::move(child));
|
||||
}
|
||||
}
|
||||
|
||||
// Component override.
|
||||
bool OnEvent(Event event) override {
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
if (!Focused())
|
||||
if (!Focused()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ActiveChild() && ActiveChild()->OnEvent(event))
|
||||
if (ActiveChild() && ActiveChild()->OnEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return EventHandler(event);
|
||||
}
|
||||
|
||||
Component ActiveChild() override {
|
||||
if (children_.size() == 0)
|
||||
if (children_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return children_[*selector_ % children_.size()];
|
||||
}
|
||||
@@ -45,7 +50,7 @@ class ContainerBase : public ComponentBase {
|
||||
void SetActiveChild(ComponentBase* child) override {
|
||||
for (size_t i = 0; i < children_.size(); ++i) {
|
||||
if (children_[i].get() == child) {
|
||||
*selector_ = i;
|
||||
*selector_ = (int)i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -53,10 +58,10 @@ class ContainerBase : public ComponentBase {
|
||||
|
||||
protected:
|
||||
// Handlers
|
||||
virtual bool EventHandler(Event) { return false; }
|
||||
virtual bool EventHandler(Event /*unused*/) { return false; } // NOLINT
|
||||
|
||||
virtual bool OnMouseEvent(Event event) {
|
||||
return ComponentBase::OnEvent(event);
|
||||
return ComponentBase::OnEvent(std::move(event));
|
||||
}
|
||||
|
||||
int selected_ = 0;
|
||||
@@ -71,11 +76,16 @@ class ContainerBase : public ComponentBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveSelectorWrap(int dir) {
|
||||
if (children_.empty()) {
|
||||
return;
|
||||
}
|
||||
for (size_t offset = 1; offset < children_.size(); ++offset) {
|
||||
int i = (*selector_ + offset * dir + children_.size()) % children_.size();
|
||||
size_t i = ((size_t(*selector_ + offset * dir + children_.size())) %
|
||||
children_.size());
|
||||
if (children_[i]->Focusable()) {
|
||||
*selector_ = i;
|
||||
*selector_ = (int)i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -88,60 +98,74 @@ class VerticalContainer : public ContainerBase {
|
||||
|
||||
Element Render() override {
|
||||
Elements elements;
|
||||
for (auto& it : children_)
|
||||
for (auto& it : children_) {
|
||||
elements.push_back(it->Render());
|
||||
if (elements.size() == 0)
|
||||
}
|
||||
if (elements.empty()) {
|
||||
return text("Empty container") | reflect(box_);
|
||||
}
|
||||
return vbox(std::move(elements)) | reflect(box_);
|
||||
}
|
||||
|
||||
bool EventHandler(Event event) override {
|
||||
int old_selected = *selector_;
|
||||
if (event == Event::ArrowUp || event == Event::Character('k'))
|
||||
if (event == Event::ArrowUp || event == Event::Character('k')) {
|
||||
MoveSelector(-1);
|
||||
if (event == Event::ArrowDown || event == Event::Character('j'))
|
||||
}
|
||||
if (event == Event::ArrowDown || event == Event::Character('j')) {
|
||||
MoveSelector(+1);
|
||||
}
|
||||
if (event == Event::PageUp) {
|
||||
for (int i = 0; i < box_.y_max - box_.y_min; ++i)
|
||||
for (int i = 0; i < box_.y_max - box_.y_min; ++i) {
|
||||
MoveSelector(-1);
|
||||
}
|
||||
}
|
||||
if (event == Event::PageDown) {
|
||||
for (int i = 0; i < box_.y_max - box_.y_min; ++i)
|
||||
for (int i = 0; i < box_.y_max - box_.y_min; ++i) {
|
||||
MoveSelector(1);
|
||||
}
|
||||
}
|
||||
if (event == Event::Home) {
|
||||
for (size_t i = 0; i < children_.size(); ++i)
|
||||
for (size_t i = 0; i < children_.size(); ++i) {
|
||||
MoveSelector(-1);
|
||||
}
|
||||
}
|
||||
if (event == Event::End) {
|
||||
for (size_t i = 0; i < children_.size(); ++i)
|
||||
for (size_t i = 0; i < children_.size(); ++i) {
|
||||
MoveSelector(1);
|
||||
}
|
||||
}
|
||||
if (event == Event::Tab && children_.size())
|
||||
if (event == Event::Tab) {
|
||||
MoveSelectorWrap(+1);
|
||||
if (event == Event::TabReverse && children_.size())
|
||||
}
|
||||
if (event == Event::TabReverse) {
|
||||
MoveSelectorWrap(-1);
|
||||
}
|
||||
|
||||
*selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_));
|
||||
return old_selected != *selector_;
|
||||
}
|
||||
|
||||
bool OnMouseEvent(Event event) override {
|
||||
if (ContainerBase::OnMouseEvent(event))
|
||||
if (ContainerBase::OnMouseEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.mouse().button != Mouse::WheelUp &&
|
||||
event.mouse().button != Mouse::WheelDown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!box_.Contain(event.mouse().x, event.mouse().y))
|
||||
if (!box_.Contain(event.mouse().x, event.mouse().y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::WheelUp)
|
||||
if (event.mouse().button == Mouse::WheelUp) {
|
||||
MoveSelector(-1);
|
||||
if (event.mouse().button == Mouse::WheelDown)
|
||||
}
|
||||
if (event.mouse().button == Mouse::WheelDown) {
|
||||
MoveSelector(+1);
|
||||
}
|
||||
*selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_));
|
||||
|
||||
return true;
|
||||
@@ -156,23 +180,29 @@ class HorizontalContainer : public ContainerBase {
|
||||
|
||||
Element Render() override {
|
||||
Elements elements;
|
||||
for (auto& it : children_)
|
||||
for (auto& it : children_) {
|
||||
elements.push_back(it->Render());
|
||||
if (elements.size() == 0)
|
||||
}
|
||||
if (elements.empty()) {
|
||||
return text("Empty container");
|
||||
}
|
||||
return hbox(std::move(elements));
|
||||
}
|
||||
|
||||
bool EventHandler(Event event) override {
|
||||
int old_selected = *selector_;
|
||||
if (event == Event::ArrowLeft || event == Event::Character('h'))
|
||||
if (event == Event::ArrowLeft || event == Event::Character('h')) {
|
||||
MoveSelector(-1);
|
||||
if (event == Event::ArrowRight || event == Event::Character('l'))
|
||||
}
|
||||
if (event == Event::ArrowRight || event == Event::Character('l')) {
|
||||
MoveSelector(+1);
|
||||
if (event == Event::Tab && children_.size())
|
||||
}
|
||||
if (event == Event::Tab) {
|
||||
MoveSelectorWrap(+1);
|
||||
if (event == Event::TabReverse && children_.size())
|
||||
}
|
||||
if (event == Event::TabReverse) {
|
||||
MoveSelectorWrap(-1);
|
||||
}
|
||||
|
||||
*selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_));
|
||||
return old_selected != *selector_;
|
||||
@@ -185,14 +215,16 @@ class TabContainer : public ContainerBase {
|
||||
|
||||
Element Render() override {
|
||||
Component active_child = ActiveChild();
|
||||
if (active_child)
|
||||
if (active_child) {
|
||||
return active_child->Render();
|
||||
}
|
||||
return text("Empty container");
|
||||
}
|
||||
|
||||
bool Focusable() const override {
|
||||
if (children_.size() == 0)
|
||||
if (children_.empty()) {
|
||||
return false;
|
||||
}
|
||||
return children_[*selector_ % children_.size()]->Focusable();
|
||||
}
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
#include <algorithm> // for max, min
|
||||
#include <memory> // for __shared_ptr_access
|
||||
#include <string> // for string
|
||||
#include <utility> // for move
|
||||
#include <algorithm> // for max, min
|
||||
#include <functional> // for function
|
||||
#include <memory> // for __shared_ptr_access, shared_ptr, allocator
|
||||
#include <string> // for string
|
||||
|
||||
#include "ftxui/component/component.hpp" // for Maybe, Checkbox, Make, Radiobox, Vertical, Dropdown
|
||||
#include "ftxui/component/component_base.hpp" // for Component, ComponentBase
|
||||
#include "ftxui/component/component_options.hpp" // for CheckboxOption
|
||||
#include "ftxui/dom/elements.hpp" // for operator|, Element, border, filler, separator, size, vbox, frame, vscroll_indicator, HEIGHT, LESS_THAN
|
||||
#include "ftxui/component/component_options.hpp" // for CheckboxOption, EntryState
|
||||
#include "ftxui/dom/elements.hpp" // for operator|, Element, border, filler, operator|=, separator, size, text, vbox, frame, vscroll_indicator, hbox, HEIGHT, LESS_THAN, bold, inverted
|
||||
#include "ftxui/util/ref.hpp" // for ConstStringListRef
|
||||
|
||||
namespace ftxui {
|
||||
@@ -15,15 +15,17 @@ Component Dropdown(ConstStringListRef entries, int* selected) {
|
||||
class Impl : public ComponentBase {
|
||||
public:
|
||||
Impl(ConstStringListRef entries, int* selected)
|
||||
: entries_(std::move(entries)), selected_(selected) {
|
||||
: entries_(entries), selected_(selected) {
|
||||
CheckboxOption option;
|
||||
option.transform = [](EntryState s) {
|
||||
auto prefix = text(s.state ? "↓ " : "→ ");
|
||||
option.transform = [](const EntryState& s) {
|
||||
auto prefix = text(s.state ? "↓ " : "→ "); // NOLINT
|
||||
auto t = text(s.label);
|
||||
if (s.active)
|
||||
if (s.active) {
|
||||
t |= bold;
|
||||
if (s.focused)
|
||||
}
|
||||
if (s.focused) {
|
||||
t |= inverted;
|
||||
}
|
||||
return hbox({prefix, t});
|
||||
};
|
||||
checkbox_ = Checkbox(&title_, &show_, option),
|
||||
@@ -39,11 +41,12 @@ Component Dropdown(ConstStringListRef entries, int* selected) {
|
||||
*selected_ = std::min((int)entries_.size() - 1, std::max(0, *selected_));
|
||||
title_ = entries_[*selected_];
|
||||
if (show_) {
|
||||
const int max_height = 12;
|
||||
return vbox({
|
||||
checkbox_->Render(),
|
||||
separator(),
|
||||
radiobox_->Render() | vscroll_indicator | frame |
|
||||
size(HEIGHT, LESS_THAN, 12),
|
||||
size(HEIGHT, LESS_THAN, max_height),
|
||||
}) |
|
||||
border;
|
||||
}
|
||||
@@ -63,7 +66,7 @@ Component Dropdown(ConstStringListRef entries, int* selected) {
|
||||
Component radiobox_;
|
||||
};
|
||||
|
||||
return Make<Impl>(std::move(entries), selected);
|
||||
return Make<Impl>(entries, selected);
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -29,7 +29,7 @@ Event Event::Mouse(std::string input, struct Mouse mouse) {
|
||||
Event event;
|
||||
event.input_ = std::move(input);
|
||||
event.type_ = Type::Mouse;
|
||||
event.mouse_ = mouse;
|
||||
event.mouse_ = mouse; // NOLINT
|
||||
return event;
|
||||
}
|
||||
|
||||
@@ -45,40 +45,39 @@ Event Event::CursorReporting(std::string input, int x, int y) {
|
||||
Event event;
|
||||
event.input_ = std::move(input);
|
||||
event.type_ = Type::CursorReporting;
|
||||
event.cursor_.x = x;
|
||||
event.cursor_.y = y;
|
||||
event.cursor_.x = x; // NOLINT
|
||||
event.cursor_.y = y; // NOLINT
|
||||
return event;
|
||||
}
|
||||
|
||||
// --- Arrow ---
|
||||
const Event Event::ArrowLeft = Event::Special("\x1B[D");
|
||||
const Event Event::ArrowRight = Event::Special("\x1B[C");
|
||||
const Event Event::ArrowUp = Event::Special("\x1B[A");
|
||||
const Event Event::ArrowDown = Event::Special("\x1B[B");
|
||||
const Event Event::Backspace = Event::Special({127});
|
||||
const Event Event::Delete = Event::Special("\x1B[3~");
|
||||
const Event Event::Escape = Event::Special("\x1B");
|
||||
const Event Event::Return = Event::Special({10});
|
||||
const Event Event::Tab = Event::Special({9});
|
||||
const Event Event::TabReverse = Event::Special({27, 91, 90});
|
||||
const Event Event::F1 = Event::Special("\x1B[OP");
|
||||
const Event Event::F2 = Event::Special("\x1B[OQ");
|
||||
const Event Event::F3 = Event::Special("\x1B[OR");
|
||||
const Event Event::F4 = Event::Special("\x1B[OS");
|
||||
const Event Event::F5 = Event::Special("\x1B[15~");
|
||||
const Event Event::F6 = Event::Special("\x1B[17~");
|
||||
const Event Event::F7 = Event::Special("\x1B[18~");
|
||||
const Event Event::F8 = Event::Special("\x1B[19~");
|
||||
const Event Event::F9 = Event::Special("\x1B[20~");
|
||||
const Event Event::F10 = Event::Special("\x1B[21~");
|
||||
const Event Event::F11 = Event::Special("\x1B[21~"); // Doesn't exist
|
||||
const Event Event::F12 = Event::Special("\x1B[24~");
|
||||
const Event Event::Home = Event::Special({27, 91, 72});
|
||||
const Event Event::End = Event::Special({27, 91, 70});
|
||||
const Event Event::PageUp = Event::Special({27, 91, 53, 126});
|
||||
const Event Event::PageDown = Event::Special({27, 91, 54, 126});
|
||||
|
||||
Event Event::Custom = Event::Special({0});
|
||||
const Event Event::ArrowLeft = Event::Special("\x1B[D"); // NOLINT
|
||||
const Event Event::ArrowRight = Event::Special("\x1B[C"); // NOLINT
|
||||
const Event Event::ArrowUp = Event::Special("\x1B[A"); // NOLINT
|
||||
const Event Event::ArrowDown = Event::Special("\x1B[B"); // NOLINT
|
||||
const Event Event::Backspace = Event::Special({127}); // NOLINT
|
||||
const Event Event::Delete = Event::Special("\x1B[3~"); // NOLINT
|
||||
const Event Event::Escape = Event::Special("\x1B"); // NOLINT
|
||||
const Event Event::Return = Event::Special({10}); // NOLINT
|
||||
const Event Event::Tab = Event::Special({9}); // NOLINT
|
||||
const Event Event::TabReverse = Event::Special({27, 91, 90}); // NOLINT
|
||||
const Event Event::F1 = Event::Special("\x1B[OP"); // NOLINT
|
||||
const Event Event::F2 = Event::Special("\x1B[OQ"); // NOLINT
|
||||
const Event Event::F3 = Event::Special("\x1B[OR"); // NOLINT
|
||||
const Event Event::F4 = Event::Special("\x1B[OS"); // NOLINT
|
||||
const Event Event::F5 = Event::Special("\x1B[15~"); // NOLINT
|
||||
const Event Event::F6 = Event::Special("\x1B[17~"); // NOLINT
|
||||
const Event Event::F7 = Event::Special("\x1B[18~"); // NOLINT
|
||||
const Event Event::F8 = Event::Special("\x1B[19~"); // NOLINT
|
||||
const Event Event::F9 = Event::Special("\x1B[20~"); // NOLINT
|
||||
const Event Event::F10 = Event::Special("\x1B[21~"); // NOLINT
|
||||
const Event Event::F11 = Event::Special("\x1B[21~"); // Doesn't exist // NOLINT
|
||||
const Event Event::F12 = Event::Special("\x1B[24~"); // NOLINT
|
||||
const Event Event::Home = Event::Special({27, 91, 72}); // NOLINT
|
||||
const Event Event::End = Event::Special({27, 91, 70}); // NOLINT
|
||||
const Event Event::PageUp = Event::Special({27, 91, 53, 126}); // NOLINT
|
||||
const Event Event::PageDown = Event::Special({27, 91, 54, 126}); // NOLINT
|
||||
const Event Event::Custom = Event::Special({0}); // NOLINT
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include <stddef.h> // for size_t
|
||||
#include <algorithm> // for max, min
|
||||
#include <cstddef> // for size_t
|
||||
#include <functional> // for function
|
||||
#include <memory> // for shared_ptr, allocator
|
||||
#include <string> // for string, wstring
|
||||
@@ -24,11 +24,12 @@ namespace ftxui {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string PasswordField(int size) {
|
||||
std::string PasswordField(size_t size) {
|
||||
std::string out;
|
||||
out.reserve(2 * size);
|
||||
while (size--)
|
||||
while (size--) {
|
||||
out += "•";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -38,21 +39,25 @@ class InputBase : public ComponentBase {
|
||||
InputBase(StringRef content,
|
||||
ConstStringRef placeholder,
|
||||
Ref<InputOption> option)
|
||||
: content_(content), placeholder_(placeholder), option_(option) {}
|
||||
: content_(std::move(content)),
|
||||
placeholder_(std::move(placeholder)),
|
||||
option_(std::move(option)) {}
|
||||
|
||||
int cursor_position_internal_ = 0;
|
||||
int& cursor_position() {
|
||||
int& opt = option_->cursor_position();
|
||||
if (opt != -1)
|
||||
if (opt != -1) {
|
||||
return opt;
|
||||
}
|
||||
return cursor_position_internal_;
|
||||
}
|
||||
|
||||
// Component implementation:
|
||||
Element Render() override {
|
||||
std::string password_content;
|
||||
if (option_->password())
|
||||
if (option_->password()) {
|
||||
password_content = PasswordField(content_->size());
|
||||
}
|
||||
std::string& content = option_->password() ? password_content : *content_;
|
||||
|
||||
int size = GlyphCount(content);
|
||||
@@ -65,19 +70,22 @@ class InputBase : public ComponentBase {
|
||||
if (size == 0) {
|
||||
bool hovered = hovered_;
|
||||
Decorator decorator = dim | main_decorator;
|
||||
if (is_focused)
|
||||
if (is_focused) {
|
||||
decorator = decorator | focus;
|
||||
if (hovered || is_focused)
|
||||
}
|
||||
if (hovered || is_focused) {
|
||||
decorator = decorator | inverted;
|
||||
}
|
||||
return text(*placeholder_) | decorator | reflect(box_);
|
||||
}
|
||||
|
||||
// Not focused.
|
||||
if (!is_focused) {
|
||||
if (hovered_)
|
||||
if (hovered_) {
|
||||
return text(content) | main_decorator | inverted | reflect(box_);
|
||||
else
|
||||
} else {
|
||||
return text(content) | main_decorator | reflect(box_);
|
||||
}
|
||||
}
|
||||
|
||||
int index_before_cursor = GlyphPosition(content, cursor_position());
|
||||
@@ -100,17 +108,19 @@ class InputBase : public ComponentBase {
|
||||
|
||||
bool OnEvent(Event event) override {
|
||||
cursor_position() =
|
||||
std::max(0, std::min<int>(content_->size(), cursor_position()));
|
||||
std::max(0, std::min<int>((int)content_->size(), cursor_position()));
|
||||
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
std::string c;
|
||||
|
||||
// Backspace.
|
||||
if (event == Event::Backspace) {
|
||||
if (cursor_position() == 0)
|
||||
if (cursor_position() == 0) {
|
||||
return false;
|
||||
}
|
||||
size_t start = GlyphPosition(*content_, cursor_position() - 1);
|
||||
size_t end = GlyphPosition(*content_, cursor_position());
|
||||
content_->erase(start, end - start);
|
||||
@@ -121,8 +131,9 @@ class InputBase : public ComponentBase {
|
||||
|
||||
// Delete
|
||||
if (event == Event::Delete) {
|
||||
if (cursor_position() == int(content_->size()))
|
||||
if (cursor_position() == int(content_->size())) {
|
||||
return false;
|
||||
}
|
||||
size_t start = GlyphPosition(*content_, cursor_position());
|
||||
size_t end = GlyphPosition(*content_, cursor_position() + 1);
|
||||
content_->erase(start, end - start);
|
||||
@@ -176,8 +187,9 @@ class InputBase : public ComponentBase {
|
||||
bool OnMouseEvent(Event event) {
|
||||
hovered_ =
|
||||
box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event);
|
||||
if (!hovered_)
|
||||
if (!hovered_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button != Mouse::Left ||
|
||||
event.mouse().motion != Mouse::Pressed) {
|
||||
@@ -185,22 +197,24 @@ class InputBase : public ComponentBase {
|
||||
}
|
||||
|
||||
TakeFocus();
|
||||
if (content_->size() == 0)
|
||||
if (content_->empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto mapping = CellToGlyphIndex(*content_);
|
||||
int original_glyph = cursor_position();
|
||||
original_glyph = util::clamp(original_glyph, 0, int(mapping.size()));
|
||||
int original_cell = 0;
|
||||
size_t original_cell = 0;
|
||||
for (size_t i = 0; i < mapping.size(); i++) {
|
||||
if (mapping[i] == original_glyph) {
|
||||
original_cell = i;
|
||||
original_cell = (int)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mapping[original_cell] != original_glyph)
|
||||
if (mapping[original_cell] != original_glyph) {
|
||||
original_cell = mapping.size();
|
||||
int target_cell = original_cell + event.mouse().x - cursor_box_.x_min;
|
||||
}
|
||||
int target_cell = int(original_cell) + event.mouse().x - cursor_box_.x_min;
|
||||
int target_glyph = target_cell < (int)mapping.size() ? mapping[target_cell]
|
||||
: (int)mapping.size();
|
||||
target_glyph = util::clamp(target_glyph, 0, GlyphCount(*content_));
|
||||
@@ -279,7 +293,8 @@ class WideInputBase : public InputBase {
|
||||
Component Input(StringRef content,
|
||||
ConstStringRef placeholder,
|
||||
Ref<InputOption> option) {
|
||||
return Make<InputBase>(content, placeholder, std::move(option));
|
||||
return Make<InputBase>(std::move(content), std::move(placeholder),
|
||||
std::move(option));
|
||||
}
|
||||
|
||||
/// @brief . An input box for editing text.
|
||||
@@ -307,7 +322,8 @@ Component Input(StringRef content,
|
||||
Component Input(WideStringRef content,
|
||||
ConstStringRef placeholder,
|
||||
Ref<InputOption> option) {
|
||||
return Make<WideInputBase>(content, placeholder, std::move(option));
|
||||
return Make<WideInputBase>(std::move(content), std::move(placeholder),
|
||||
std::move(option));
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -13,7 +13,7 @@ namespace ftxui {
|
||||
Component Maybe(Component child, std::function<bool()> show) {
|
||||
class Impl : public ComponentBase {
|
||||
public:
|
||||
Impl(std::function<bool()> show) : show_(std::move(show)) {}
|
||||
explicit Impl(std::function<bool()> show) : show_(std::move(show)) {}
|
||||
|
||||
private:
|
||||
Element Render() override {
|
||||
@@ -48,7 +48,7 @@ Component Maybe(Component child, std::function<bool()> show) {
|
||||
/// ```
|
||||
ComponentDecorator Maybe(std::function<bool()> show) {
|
||||
return [show = std::move(show)](Component child) mutable {
|
||||
return Maybe(child, std::move(show));
|
||||
return Maybe(std::move(child), std::move(show));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ ComponentDecorator Maybe(std::function<bool()> show) {
|
||||
/// auto maybe_component = Maybe(component, &show);
|
||||
/// ```
|
||||
Component Maybe(Component child, const bool* show) {
|
||||
return Maybe(child, [show] { return *show; });
|
||||
return Maybe(std::move(child), [show] { return *show; });
|
||||
}
|
||||
|
||||
/// @brief Decorate a component. It is shown only when |show| is true.
|
||||
@@ -78,7 +78,7 @@ Component Maybe(Component child, const bool* show) {
|
||||
/// auto maybe_component = component | Maybe(&show);
|
||||
/// ```
|
||||
ComponentDecorator Maybe(const bool* show) {
|
||||
return [show](Component child) { return Maybe(child, show); };
|
||||
return [show](Component child) { return Maybe(std::move(child), show); };
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -24,13 +24,15 @@ namespace ftxui {
|
||||
|
||||
namespace {
|
||||
|
||||
Element DefaultOptionTransform(EntryState state) {
|
||||
state.label = (state.active ? "> " : " ") + state.label;
|
||||
Element e = text(state.label);
|
||||
if (state.focused)
|
||||
Element DefaultOptionTransform(const EntryState& state) {
|
||||
std::string label = (state.active ? "> " : " ") + state.label; // NOLINT
|
||||
Element e = text(label);
|
||||
if (state.focused) {
|
||||
e = e | inverted;
|
||||
if (state.active)
|
||||
}
|
||||
if (state.active) {
|
||||
e = e | bold;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -43,7 +45,7 @@ bool IsInverted(MenuOption::Direction direction) {
|
||||
case MenuOption::Direction::Right:
|
||||
return false;
|
||||
}
|
||||
return false; // NOT_REACHED()
|
||||
return false; // NOT_REACHED()
|
||||
}
|
||||
|
||||
bool IsHorizontal(MenuOption::Direction direction) {
|
||||
@@ -55,7 +57,7 @@ bool IsHorizontal(MenuOption::Direction direction) {
|
||||
case MenuOption::Direction::Up:
|
||||
return false;
|
||||
}
|
||||
return false; // NOT_REACHED()
|
||||
return false; // NOT_REACHED()
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -65,17 +67,19 @@ bool IsHorizontal(MenuOption::Direction direction) {
|
||||
class MenuBase : public ComponentBase {
|
||||
public:
|
||||
MenuBase(ConstStringListRef entries, int* selected, Ref<MenuOption> option)
|
||||
: entries_(entries), selected_(selected), option_(option) {}
|
||||
: entries_(entries), selected_(selected), option_(std::move(option)) {}
|
||||
|
||||
bool IsHorizontal() { return ftxui::IsHorizontal(option_->direction); }
|
||||
void OnChange() {
|
||||
if (option_->on_change)
|
||||
if (option_->on_change) {
|
||||
option_->on_change();
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnter() {
|
||||
if (option_->on_enter)
|
||||
if (option_->on_enter) {
|
||||
option_->on_enter();
|
||||
}
|
||||
}
|
||||
|
||||
void Clamp() {
|
||||
@@ -87,10 +91,12 @@ class MenuBase : public ComponentBase {
|
||||
void OnAnimation(animation::Params& params) override {
|
||||
animator_first_.OnAnimation(params);
|
||||
animator_second_.OnAnimation(params);
|
||||
for (auto& animator : animator_background_)
|
||||
for (auto& animator : animator_background_) {
|
||||
animator.OnAnimation(params);
|
||||
for (auto& animator : animator_foreground_)
|
||||
}
|
||||
for (auto& animator : animator_foreground_) {
|
||||
animator.OnAnimation(params);
|
||||
}
|
||||
}
|
||||
|
||||
Element Render() override {
|
||||
@@ -99,11 +105,13 @@ class MenuBase : public ComponentBase {
|
||||
|
||||
Elements elements;
|
||||
bool is_menu_focused = Focused();
|
||||
if (option_->elements_prefix)
|
||||
if (option_->elements_prefix) {
|
||||
elements.push_back(option_->elements_prefix());
|
||||
}
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
if (i != 0 && option_->elements_infix)
|
||||
if (i != 0 && option_->elements_infix) {
|
||||
elements.push_back(option_->elements_infix());
|
||||
}
|
||||
bool is_focused = (focused_entry() == i) && is_menu_focused;
|
||||
bool is_selected = (*selected_ == i);
|
||||
|
||||
@@ -120,21 +128,24 @@ class MenuBase : public ComponentBase {
|
||||
Element element =
|
||||
(option_->entries.transform ? option_->entries.transform
|
||||
: DefaultOptionTransform) //
|
||||
(std::move(state));
|
||||
(state);
|
||||
elements.push_back(element | AnimatedColorStyle(i) | reflect(boxes_[i]) |
|
||||
focus_management);
|
||||
}
|
||||
if (option_->elements_postfix)
|
||||
if (option_->elements_postfix) {
|
||||
elements.push_back(option_->elements_postfix());
|
||||
}
|
||||
|
||||
if (IsInverted(option_->direction))
|
||||
if (IsInverted(option_->direction)) {
|
||||
std::reverse(elements.begin(), elements.end());
|
||||
}
|
||||
|
||||
Element bar =
|
||||
IsHorizontal() ? hbox(std::move(elements)) : vbox(std::move(elements));
|
||||
|
||||
if (!option_->underline.enabled)
|
||||
if (!option_->underline.enabled) {
|
||||
return bar | reflect(box_);
|
||||
}
|
||||
|
||||
if (IsHorizontal()) {
|
||||
return vbox({
|
||||
@@ -211,36 +222,49 @@ class MenuBase : public ComponentBase {
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
bool OnEvent(Event event) override {
|
||||
Clamp();
|
||||
if (!CaptureMouse(event))
|
||||
if (!CaptureMouse(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
if (Focused()) {
|
||||
int old_selected = *selected_;
|
||||
if (event == Event::ArrowUp || event == Event::Character('k'))
|
||||
if (event == Event::ArrowUp || event == Event::Character('k')) {
|
||||
OnUp();
|
||||
if (event == Event::ArrowDown || event == Event::Character('j'))
|
||||
}
|
||||
if (event == Event::ArrowDown || event == Event::Character('j')) {
|
||||
OnDown();
|
||||
if (event == Event::ArrowLeft || event == Event::Character('h'))
|
||||
}
|
||||
if (event == Event::ArrowLeft || event == Event::Character('h')) {
|
||||
OnLeft();
|
||||
if (event == Event::ArrowRight || event == Event::Character('l'))
|
||||
}
|
||||
if (event == Event::ArrowRight || event == Event::Character('l')) {
|
||||
OnRight();
|
||||
if (event == Event::PageUp)
|
||||
}
|
||||
if (event == Event::PageUp) {
|
||||
(*selected_) -= box_.y_max - box_.y_min;
|
||||
if (event == Event::PageDown)
|
||||
}
|
||||
if (event == Event::PageDown) {
|
||||
(*selected_) += box_.y_max - box_.y_min;
|
||||
if (event == Event::Home)
|
||||
}
|
||||
if (event == Event::Home) {
|
||||
(*selected_) = 0;
|
||||
if (event == Event::End)
|
||||
}
|
||||
if (event == Event::End) {
|
||||
(*selected_) = size() - 1;
|
||||
if (event == Event::Tab && size())
|
||||
}
|
||||
if (event == Event::Tab && size()) {
|
||||
*selected_ = (*selected_ + 1) % size();
|
||||
if (event == Event::TabReverse && size())
|
||||
}
|
||||
if (event == Event::TabReverse && size()) {
|
||||
*selected_ = (*selected_ + size() - 1) % size();
|
||||
}
|
||||
|
||||
*selected_ = util::clamp(*selected_, 0, size() - 1);
|
||||
|
||||
@@ -269,11 +293,13 @@ class MenuBase : public ComponentBase {
|
||||
event.mouse().button != Mouse::Left) {
|
||||
return false;
|
||||
}
|
||||
if (!CaptureMouse(event))
|
||||
if (!CaptureMouse(event)) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
if (!boxes_[i].Contain(event.mouse().x, event.mouse().y))
|
||||
if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TakeFocus();
|
||||
focused_entry() = i;
|
||||
@@ -290,19 +316,23 @@ class MenuBase : public ComponentBase {
|
||||
}
|
||||
|
||||
bool OnMouseWheel(Event event) {
|
||||
if (!box_.Contain(event.mouse().x, event.mouse().y))
|
||||
if (!box_.Contain(event.mouse().x, event.mouse().y)) {
|
||||
return false;
|
||||
}
|
||||
int old_selected = *selected_;
|
||||
|
||||
if (event.mouse().button == Mouse::WheelUp)
|
||||
if (event.mouse().button == Mouse::WheelUp) {
|
||||
(*selected_)--;
|
||||
if (event.mouse().button == Mouse::WheelDown)
|
||||
}
|
||||
if (event.mouse().button == Mouse::WheelDown) {
|
||||
(*selected_)++;
|
||||
}
|
||||
|
||||
*selected_ = util::clamp(*selected_, 0, size() - 1);
|
||||
|
||||
if (*selected_ != old_selected)
|
||||
if (*selected_ != old_selected) {
|
||||
OnChange();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -319,12 +349,12 @@ class MenuBase : public ComponentBase {
|
||||
animator_foreground_.clear();
|
||||
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
animation_background_[i] = 0.f;
|
||||
animation_foreground_[i] = 0.f;
|
||||
animator_background_.emplace_back(&animation_background_[i], 0.f,
|
||||
animation_background_[i] = 0.F;
|
||||
animation_foreground_[i] = 0.F;
|
||||
animator_background_.emplace_back(&animation_background_[i], 0.F,
|
||||
std::chrono::milliseconds(0),
|
||||
animation::easing::Linear);
|
||||
animator_foreground_.emplace_back(&animation_foreground_[i], 0.f,
|
||||
animator_foreground_.emplace_back(&animation_foreground_[i], 0.F,
|
||||
std::chrono::milliseconds(0),
|
||||
animation::easing::Linear);
|
||||
}
|
||||
@@ -334,7 +364,7 @@ class MenuBase : public ComponentBase {
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
bool is_focused = (focused_entry() == i) && is_menu_focused;
|
||||
bool is_selected = (*selected_ == i);
|
||||
float target = is_selected ? 1.f : is_focused ? 0.5f : 0.f;
|
||||
float target = is_selected ? 1.F : is_focused ? 0.5F : 0.F; // NOLINT
|
||||
if (animator_background_[i].to() != target) {
|
||||
animator_background_[i] = animation::Animator(
|
||||
&animation_background_[i], target,
|
||||
@@ -367,8 +397,9 @@ class MenuBase : public ComponentBase {
|
||||
}
|
||||
|
||||
void UpdateUnderlineTarget() {
|
||||
if (!option_->underline.enabled)
|
||||
if (!option_->underline.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (FirstTarget() == animator_first_.to() &&
|
||||
SecondTarget() == animator_second_.to()) {
|
||||
@@ -398,32 +429,36 @@ class MenuBase : public ComponentBase {
|
||||
|
||||
bool Focusable() const final { return entries_.size(); }
|
||||
int& focused_entry() { return option_->focused_entry(); }
|
||||
int size() const { return entries_.size(); }
|
||||
int FirstTarget() {
|
||||
if (boxes_.size() == 0)
|
||||
return 0;
|
||||
return IsHorizontal() ? boxes_[*selected_].x_min - box_.x_min
|
||||
: boxes_[*selected_].y_min - box_.y_min;
|
||||
int size() const { return int(entries_.size()); }
|
||||
float FirstTarget() {
|
||||
if (boxes_.empty()) {
|
||||
return 0.F;
|
||||
}
|
||||
int value = IsHorizontal() ? boxes_[*selected_].x_min - box_.x_min
|
||||
: boxes_[*selected_].y_min - box_.y_min;
|
||||
return float(value);
|
||||
}
|
||||
int SecondTarget() {
|
||||
if (boxes_.size() == 0)
|
||||
return 0;
|
||||
return IsHorizontal() ? boxes_[*selected_].x_max - box_.x_min
|
||||
: boxes_[*selected_].y_max - box_.y_min;
|
||||
float SecondTarget() {
|
||||
if (boxes_.empty()) {
|
||||
return 0.F;
|
||||
}
|
||||
int value = IsHorizontal() ? boxes_[*selected_].x_max - box_.x_min
|
||||
: boxes_[*selected_].y_max - box_.y_min;
|
||||
return float(value);
|
||||
}
|
||||
|
||||
protected:
|
||||
ConstStringListRef entries_;
|
||||
int* selected_ = 0;
|
||||
int* selected_ = nullptr;
|
||||
Ref<MenuOption> option_;
|
||||
|
||||
std::vector<Box> boxes_;
|
||||
Box box_;
|
||||
|
||||
float first_ = 0.f;
|
||||
float second_ = 0.f;
|
||||
animation::Animator animator_first_ = animation::Animator(&first_, 0.f);
|
||||
animation::Animator animator_second_ = animation::Animator(&second_, 0.f);
|
||||
float first_ = 0.F;
|
||||
float second_ = 0.F;
|
||||
animation::Animator animator_first_ = animation::Animator(&first_, 0.F);
|
||||
animation::Animator animator_second_ = animation::Animator(&second_, 0.F);
|
||||
|
||||
std::vector<animation::Animator> animator_background_;
|
||||
std::vector<animation::Animator> animator_foreground_;
|
||||
@@ -519,7 +554,7 @@ Component MenuEntry(ConstStringRef label, Ref<MenuEntryOption> option) {
|
||||
|
||||
Element element =
|
||||
(option_->transform ? option_->transform : DefaultOptionTransform) //
|
||||
(std::move(state));
|
||||
(state);
|
||||
|
||||
auto focus_management = focused ? select : nothing;
|
||||
return element | AnimatedColorStyle() | focus_management | reflect(box_);
|
||||
@@ -527,9 +562,10 @@ Component MenuEntry(ConstStringRef label, Ref<MenuEntryOption> option) {
|
||||
|
||||
void UpdateAnimationTarget() {
|
||||
bool focused = Focused();
|
||||
float target = focused ? 1.0f : hovered_ ? 0.5f : 0.0f;
|
||||
if (target == animator_background_.to())
|
||||
float target = focused ? 1.F : hovered_ ? 0.5F : 0.F; // NOLINT
|
||||
if (target == animator_background_.to()) {
|
||||
return;
|
||||
}
|
||||
animator_background_ =
|
||||
animation::Animator(&animation_background_, target,
|
||||
option_->animated_colors.background.duration,
|
||||
@@ -560,13 +596,15 @@ Component MenuEntry(ConstStringRef label, Ref<MenuEntryOption> option) {
|
||||
|
||||
bool Focusable() const override { return true; }
|
||||
bool OnEvent(Event event) override {
|
||||
if (!event.is_mouse())
|
||||
if (!event.is_mouse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hovered_ = box_.Contain(event.mouse().x, event.mouse().y);
|
||||
|
||||
if (!hovered_)
|
||||
if (!hovered_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Released) {
|
||||
@@ -587,12 +625,12 @@ Component MenuEntry(ConstStringRef label, Ref<MenuEntryOption> option) {
|
||||
Box box_;
|
||||
bool hovered_ = false;
|
||||
|
||||
float animation_background_ = 0.f;
|
||||
float animation_foreground_ = 0.f;
|
||||
float animation_background_ = 0.F;
|
||||
float animation_foreground_ = 0.F;
|
||||
animation::Animator animator_background_ =
|
||||
animation::Animator(&animation_background_, 0.f);
|
||||
animation::Animator(&animation_background_, 0.F);
|
||||
animation::Animator animator_foreground_ =
|
||||
animation::Animator(&animation_foreground_, 0.f);
|
||||
animation::Animator(&animation_foreground_, 0.F);
|
||||
};
|
||||
|
||||
return Make<Impl>(std::move(label), std::move(option));
|
||||
|
@@ -1,21 +1,20 @@
|
||||
#include <algorithm> // for max
|
||||
#include <functional> // for function
|
||||
#include <memory> // for shared_ptr, allocator_traits<>::value_type
|
||||
#include <string> // for string
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
|
||||
#include "ftxui/component/component.hpp" // for Make, Radiobox
|
||||
#include "ftxui/component/component_base.hpp" // for ComponentBase
|
||||
#include "ftxui/component/component_options.hpp" // for RadioboxOption
|
||||
#include "ftxui/component/component_options.hpp" // for RadioboxOption, EntryState
|
||||
#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowUp, Event::End, Event::Home, Event::PageDown, Event::PageUp, Event::Return, Event::Tab, Event::TabReverse
|
||||
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::WheelDown, Mouse::WheelUp, Mouse::Left, Mouse::Released
|
||||
#include "ftxui/component/screen_interactive.hpp" // for Component
|
||||
#include "ftxui/dom/elements.hpp" // for operator|, reflect, text, Element, hbox, vbox, Elements, focus, nothing, select
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
#include "ftxui/screen/util.hpp" // for clamp
|
||||
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef
|
||||
#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, vbox, Elements, focus, nothing, select
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
#include "ftxui/screen/util.hpp" // for clamp
|
||||
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
@@ -50,41 +49,51 @@ class RadioboxBase : public ComponentBase {
|
||||
is_focused,
|
||||
};
|
||||
auto element =
|
||||
(option_->transform
|
||||
? option_->transform
|
||||
: RadioboxOption::Simple().transform)(std::move(state));
|
||||
(option_->transform ? option_->transform
|
||||
: RadioboxOption::Simple().transform)(state);
|
||||
|
||||
elements.push_back(element | focus_management | reflect(boxes_[i]));
|
||||
}
|
||||
return vbox(std::move(elements)) | reflect(box_);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
bool OnEvent(Event event) override {
|
||||
Clamp();
|
||||
if (!CaptureMouse(event))
|
||||
if (!CaptureMouse(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
if (Focused()) {
|
||||
int old_hovered = hovered_;
|
||||
if (event == Event::ArrowUp || event == Event::Character('k'))
|
||||
if (event == Event::ArrowUp || event == Event::Character('k')) {
|
||||
(hovered_)--;
|
||||
if (event == Event::ArrowDown || event == Event::Character('j'))
|
||||
}
|
||||
if (event == Event::ArrowDown || event == Event::Character('j')) {
|
||||
(hovered_)++;
|
||||
if (event == Event::PageUp)
|
||||
}
|
||||
if (event == Event::PageUp) {
|
||||
(hovered_) -= box_.y_max - box_.y_min;
|
||||
if (event == Event::PageDown)
|
||||
}
|
||||
if (event == Event::PageDown) {
|
||||
(hovered_) += box_.y_max - box_.y_min;
|
||||
if (event == Event::Home)
|
||||
}
|
||||
if (event == Event::Home) {
|
||||
(hovered_) = 0;
|
||||
if (event == Event::End)
|
||||
}
|
||||
if (event == Event::End) {
|
||||
(hovered_) = size() - 1;
|
||||
if (event == Event::Tab && size())
|
||||
}
|
||||
if (event == Event::Tab && size()) {
|
||||
hovered_ = (hovered_ + 1) % size();
|
||||
if (event == Event::TabReverse && size())
|
||||
}
|
||||
if (event == Event::TabReverse && size()) {
|
||||
hovered_ = (hovered_ + size() - 1) % size();
|
||||
}
|
||||
|
||||
hovered_ = util::clamp(hovered_, 0, size() - 1);
|
||||
|
||||
@@ -111,8 +120,9 @@ class RadioboxBase : public ComponentBase {
|
||||
}
|
||||
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
if (!boxes_[i].Contain(event.mouse().x, event.mouse().y))
|
||||
if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TakeFocus();
|
||||
focused_entry() = i;
|
||||
@@ -130,20 +140,24 @@ class RadioboxBase : public ComponentBase {
|
||||
}
|
||||
|
||||
bool OnMouseWheel(Event event) {
|
||||
if (!box_.Contain(event.mouse().x, event.mouse().y))
|
||||
if (!box_.Contain(event.mouse().x, event.mouse().y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int old_hovered = hovered_;
|
||||
|
||||
if (event.mouse().button == Mouse::WheelUp)
|
||||
if (event.mouse().button == Mouse::WheelUp) {
|
||||
(hovered_)--;
|
||||
if (event.mouse().button == Mouse::WheelDown)
|
||||
}
|
||||
if (event.mouse().button == Mouse::WheelDown) {
|
||||
(hovered_)++;
|
||||
}
|
||||
|
||||
hovered_ = util::clamp(hovered_, 0, size() - 1);
|
||||
|
||||
if (hovered_ != old_hovered)
|
||||
if (hovered_ != old_hovered) {
|
||||
option_->on_change();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -157,7 +171,7 @@ class RadioboxBase : public ComponentBase {
|
||||
|
||||
bool Focusable() const final { return entries_.size(); }
|
||||
int& focused_entry() { return option_->focused_entry(); }
|
||||
int size() const { return entries_.size(); }
|
||||
int size() const { return int(entries_.size()); }
|
||||
|
||||
ConstStringListRef entries_;
|
||||
int* selected_;
|
||||
|
@@ -28,7 +28,8 @@ namespace ftxui {
|
||||
Component Renderer(std::function<Element()> render) {
|
||||
class Impl : public ComponentBase {
|
||||
public:
|
||||
Impl(std::function<Element()> render) : render_(std::move(render)) {}
|
||||
explicit Impl(std::function<Element()> render)
|
||||
: render_(std::move(render)) {}
|
||||
Element Render() override { return render_(); }
|
||||
std::function<Element()> render_;
|
||||
};
|
||||
@@ -82,15 +83,17 @@ Component Renderer(Component child, std::function<Element()> render) {
|
||||
Component Renderer(std::function<Element(bool)> render) {
|
||||
class Impl : public ComponentBase {
|
||||
public:
|
||||
Impl(std::function<Element(bool)> render) : render_(std::move(render)) {}
|
||||
explicit Impl(std::function<Element(bool)> render)
|
||||
: render_(std::move(render)) {}
|
||||
|
||||
private:
|
||||
Element Render() override { return render_(Focused()) | reflect(box_); }
|
||||
bool Focusable() const override { return true; }
|
||||
bool OnEvent(Event event) override {
|
||||
if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y)) {
|
||||
if (!CaptureMouse(event))
|
||||
if (!CaptureMouse(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TakeFocus();
|
||||
}
|
||||
@@ -118,8 +121,8 @@ Component Renderer(std::function<Element(bool)> render) {
|
||||
/// | Renderer(inverted);
|
||||
/// screen.Loop(renderer);
|
||||
/// ```
|
||||
ComponentDecorator Renderer(ElementDecorator decorator) {
|
||||
return [decorator](Component component) {
|
||||
ComponentDecorator Renderer(ElementDecorator decorator) { // NOLINT
|
||||
return [decorator](Component component) { // NOLINT
|
||||
return Renderer(component, [component, decorator] {
|
||||
return component->Render() | decorator;
|
||||
});
|
||||
|
@@ -15,16 +15,19 @@ namespace {
|
||||
class ResizableSplitLeftBase : public ComponentBase {
|
||||
public:
|
||||
ResizableSplitLeftBase(Component main, Component child, int* main_size)
|
||||
: main_(main), child_(child), main_size_(main_size) {
|
||||
: main_(std::move(main)),
|
||||
child_(std::move(child)),
|
||||
main_size_(main_size) {
|
||||
Add(Container::Horizontal({
|
||||
main,
|
||||
child,
|
||||
main_,
|
||||
child_,
|
||||
}));
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) final {
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(std::move(event));
|
||||
}
|
||||
return ComponentBase::OnEvent(std::move(event));
|
||||
}
|
||||
|
||||
@@ -71,16 +74,19 @@ class ResizableSplitLeftBase : public ComponentBase {
|
||||
class ResizableSplitRightBase : public ComponentBase {
|
||||
public:
|
||||
ResizableSplitRightBase(Component main, Component child, int* main_size)
|
||||
: main_(main), child_(child), main_size_(main_size) {
|
||||
: main_(std::move(main)),
|
||||
child_(std::move(child)),
|
||||
main_size_(main_size) {
|
||||
Add(Container::Horizontal({
|
||||
child,
|
||||
main,
|
||||
child_,
|
||||
main_,
|
||||
}));
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) final {
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(std::move(event));
|
||||
}
|
||||
return ComponentBase::OnEvent(std::move(event));
|
||||
}
|
||||
|
||||
@@ -127,16 +133,19 @@ class ResizableSplitRightBase : public ComponentBase {
|
||||
class ResizableSplitTopBase : public ComponentBase {
|
||||
public:
|
||||
ResizableSplitTopBase(Component main, Component child, int* main_size)
|
||||
: main_(main), child_(child), main_size_(main_size) {
|
||||
: main_(std::move(main)),
|
||||
child_(std::move(child)),
|
||||
main_size_(main_size) {
|
||||
Add(Container::Vertical({
|
||||
main,
|
||||
child,
|
||||
main_,
|
||||
child_,
|
||||
}));
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) final {
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(std::move(event));
|
||||
}
|
||||
return ComponentBase::OnEvent(std::move(event));
|
||||
}
|
||||
|
||||
@@ -183,16 +192,19 @@ class ResizableSplitTopBase : public ComponentBase {
|
||||
class ResizableSplitBottomBase : public ComponentBase {
|
||||
public:
|
||||
ResizableSplitBottomBase(Component main, Component child, int* main_size)
|
||||
: main_(main), child_(child), main_size_(main_size) {
|
||||
: main_(std::move(main)),
|
||||
child_(std::move(child)),
|
||||
main_size_(main_size) {
|
||||
Add(Container::Vertical({
|
||||
child,
|
||||
main,
|
||||
child_,
|
||||
main_,
|
||||
}));
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) final {
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(std::move(event));
|
||||
}
|
||||
return ComponentBase::OnEvent(std::move(event));
|
||||
}
|
||||
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#include <stdio.h> // for fileno, stdin
|
||||
#include <algorithm> // for copy, max, min
|
||||
#include <chrono> // for operator-, duration, operator>=, milliseconds, time_point, common_type<>::type
|
||||
#include <array> // for array
|
||||
#include <chrono> // for operator-, milliseconds, duration, operator>=, time_point, common_type<>::type
|
||||
#include <csignal> // for signal, raise, SIGTSTP, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, SIGWINCH
|
||||
#include <cstdlib> // for NULL
|
||||
#include <cstdio> // for fileno, size_t, stdin
|
||||
#include <functional> // for function
|
||||
#include <initializer_list> // for initializer_list
|
||||
#include <iostream> // for cout, ostream, basic_ostream, operator<<, endl, flush
|
||||
#include <stack> // for stack
|
||||
#include <thread> // for thread, sleep_for
|
||||
#include <type_traits> // for decay_t
|
||||
#include <utility> // for swap, move
|
||||
#include <utility> // for move, swap
|
||||
#include <variant> // for visit
|
||||
#include <vector> // for vector
|
||||
|
||||
@@ -50,14 +50,15 @@ namespace ftxui {
|
||||
namespace animation {
|
||||
void RequestAnimationFrame() {
|
||||
auto* screen = ScreenInteractive::Active();
|
||||
if (screen)
|
||||
if (screen) {
|
||||
screen->RequestAnimationFrame();
|
||||
}
|
||||
}
|
||||
} // namespace animation
|
||||
|
||||
namespace {
|
||||
|
||||
ScreenInteractive* g_active_screen = nullptr;
|
||||
ScreenInteractive* g_active_screen = nullptr; // NOLINT
|
||||
|
||||
void Flush() {
|
||||
// Emscripten doesn't implement flush. We interpret zero as flush.
|
||||
@@ -138,16 +139,14 @@ void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
int CheckStdinReady(int usec_timeout) {
|
||||
timeval tv = {0, usec_timeout};
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
|
||||
return FD_ISSET(STDIN_FILENO, &fds);
|
||||
FD_ZERO(&fds); // NOLINT
|
||||
FD_SET(STDIN_FILENO, &fds); // NOLINT
|
||||
select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &tv); // NOLINT
|
||||
return FD_ISSET(STDIN_FILENO, &fds); // NOLINT
|
||||
}
|
||||
|
||||
// Read char from the terminal.
|
||||
void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
const int buffer_size = 100;
|
||||
|
||||
auto parser = TerminalInputParser(std::move(out));
|
||||
|
||||
while (!*quit) {
|
||||
@@ -156,16 +155,18 @@ void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char buff[buffer_size];
|
||||
int l = read(fileno(stdin), buff, buffer_size);
|
||||
for (int i = 0; i < l; ++i)
|
||||
parser.Add(buff[i]);
|
||||
const size_t buffer_size = 100;
|
||||
std::array<char, buffer_size> buffer; // NOLINT;
|
||||
int l = read(fileno(stdin), buffer.data(), buffer_size); // NOLINT
|
||||
for (int i = 0; i < l; ++i) {
|
||||
parser.Add(buffer[i]); // NOLINT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const std::string CSI = "\x1b[";
|
||||
const std::string CSI = "\x1b["; // NOLINT
|
||||
|
||||
// DEC: Digital Equipment Corporation
|
||||
enum class DECMode {
|
||||
@@ -186,12 +187,13 @@ enum class DSRMode {
|
||||
kCursor = 6,
|
||||
};
|
||||
|
||||
const std::string Serialize(std::vector<DECMode> parameters) {
|
||||
std::string Serialize(const std::vector<DECMode>& parameters) {
|
||||
bool first = true;
|
||||
std::string out;
|
||||
for (DECMode parameter : parameters) {
|
||||
if (!first)
|
||||
if (!first) {
|
||||
out += ";";
|
||||
}
|
||||
out += std::to_string(int(parameter));
|
||||
first = false;
|
||||
}
|
||||
@@ -199,22 +201,22 @@ const std::string Serialize(std::vector<DECMode> parameters) {
|
||||
}
|
||||
|
||||
// DEC Private Mode Set (DECSET)
|
||||
const std::string Set(std::vector<DECMode> parameters) {
|
||||
std::string Set(const std::vector<DECMode>& parameters) {
|
||||
return CSI + "?" + Serialize(parameters) + "h";
|
||||
}
|
||||
|
||||
// DEC Private Mode Reset (DECRST)
|
||||
const std::string Reset(std::vector<DECMode> parameters) {
|
||||
std::string Reset(const std::vector<DECMode>& parameters) {
|
||||
return CSI + "?" + Serialize(parameters) + "l";
|
||||
}
|
||||
|
||||
// Device Status Report (DSR)
|
||||
const std::string DeviceStatusReport(DSRMode ps) {
|
||||
std::string DeviceStatusReport(DSRMode ps) {
|
||||
return CSI + std::to_string(int(ps)) + "n";
|
||||
}
|
||||
|
||||
using SignalHandler = void(int);
|
||||
std::stack<Closure> on_exit_functions;
|
||||
std::stack<Closure> on_exit_functions; // NOLINT
|
||||
void OnExit(int signal) {
|
||||
(void)signal;
|
||||
while (!on_exit_functions.empty()) {
|
||||
@@ -223,14 +225,14 @@ void OnExit(int signal) {
|
||||
}
|
||||
}
|
||||
|
||||
auto install_signal_handler = [](int sig, SignalHandler handler) {
|
||||
const auto install_signal_handler = [](int sig, SignalHandler handler) {
|
||||
auto old_signal_handler = std::signal(sig, handler);
|
||||
on_exit_functions.push([=] { std::signal(sig, old_signal_handler); });
|
||||
};
|
||||
|
||||
Closure on_resize = [] {};
|
||||
Closure g_on_resize = [] {}; // NOLINT
|
||||
void OnResize(int /* signal */) {
|
||||
on_resize();
|
||||
g_on_resize();
|
||||
}
|
||||
|
||||
void OnSigStop(int /*signal*/) {
|
||||
@@ -239,17 +241,24 @@ void OnSigStop(int /*signal*/) {
|
||||
|
||||
class CapturedMouseImpl : public CapturedMouseInterface {
|
||||
public:
|
||||
CapturedMouseImpl(std::function<void(void)> callback) : callback_(callback) {}
|
||||
explicit CapturedMouseImpl(std::function<void(void)> callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
~CapturedMouseImpl() override { callback_(); }
|
||||
CapturedMouseImpl(const CapturedMouseImpl&) = delete;
|
||||
CapturedMouseImpl(CapturedMouseImpl&&) = delete;
|
||||
CapturedMouseImpl& operator=(const CapturedMouseImpl&) = delete;
|
||||
CapturedMouseImpl& operator=(CapturedMouseImpl&&) = delete;
|
||||
|
||||
private:
|
||||
std::function<void(void)> callback_;
|
||||
};
|
||||
|
||||
void AnimationListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
// Animation at around 60fps.
|
||||
const auto time_delta = std::chrono::milliseconds(15);
|
||||
while (!*quit) {
|
||||
out->Send(AnimationTask());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(15));
|
||||
std::this_thread::sleep_for(time_delta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,31 +295,36 @@ ScreenInteractive ScreenInteractive::FitComponent() {
|
||||
}
|
||||
|
||||
void ScreenInteractive::Post(Task task) {
|
||||
if (!quit_)
|
||||
task_sender_->Send(task);
|
||||
if (!quit_) {
|
||||
task_sender_->Send(std::move(task));
|
||||
}
|
||||
}
|
||||
void ScreenInteractive::PostEvent(Event event) {
|
||||
Post(event);
|
||||
}
|
||||
|
||||
void ScreenInteractive::RequestAnimationFrame() {
|
||||
if (animation_requested_)
|
||||
if (animation_requested_) {
|
||||
return;
|
||||
}
|
||||
animation_requested_ = true;
|
||||
auto now = animation::Clock::now();
|
||||
if (now - previous_animation_time >= std::chrono::milliseconds(33))
|
||||
const auto time_histeresis = std::chrono::milliseconds(33);
|
||||
if (now - previous_animation_time >= time_histeresis) {
|
||||
previous_animation_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
CapturedMouse ScreenInteractive::CaptureMouse() {
|
||||
if (mouse_captured)
|
||||
if (mouse_captured) {
|
||||
return nullptr;
|
||||
}
|
||||
mouse_captured = true;
|
||||
return std::make_unique<CapturedMouseImpl>(
|
||||
[this] { mouse_captured = false; });
|
||||
}
|
||||
|
||||
void ScreenInteractive::Loop(Component component) {
|
||||
void ScreenInteractive::Loop(Component component) { // NOLINT
|
||||
// Suspend previously active screen:
|
||||
if (g_active_screen) {
|
||||
std::swap(suspended_screen_, g_active_screen);
|
||||
@@ -324,7 +338,7 @@ void ScreenInteractive::Loop(Component component) {
|
||||
// This screen is now active:
|
||||
g_active_screen = this;
|
||||
g_active_screen->Install();
|
||||
g_active_screen->Main(component);
|
||||
g_active_screen->Main(std::move(component));
|
||||
g_active_screen->Uninstall();
|
||||
g_active_screen = nullptr;
|
||||
|
||||
@@ -348,7 +362,7 @@ void ScreenInteractive::Loop(Component component) {
|
||||
/// @brief Decorate a function. It executes the same way, but with the currently
|
||||
/// active screen terminal hooks temporarilly uninstalled during its execution.
|
||||
/// @param fn The function to decorate.
|
||||
Closure ScreenInteractive::WithRestoredIO(Closure fn) {
|
||||
Closure ScreenInteractive::WithRestoredIO(Closure fn) { // NOLINT
|
||||
return [this, fn] {
|
||||
Uninstall();
|
||||
fn();
|
||||
@@ -370,10 +384,11 @@ void ScreenInteractive::Install() {
|
||||
|
||||
// Install signal handlers to restore the terminal state on exit. The default
|
||||
// signal handlers are restored on exit.
|
||||
for (int signal : {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE})
|
||||
for (int signal : {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE}) {
|
||||
install_signal_handler(signal, OnExit);
|
||||
}
|
||||
|
||||
// Save the old terminal configuration and restore it on exit.
|
||||
// Save the old terminal configuration and restore it on exit.
|
||||
#if defined(_WIN32)
|
||||
// Enable VT processing on stdout and stdin
|
||||
auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
@@ -405,12 +420,12 @@ void ScreenInteractive::Install() {
|
||||
SetConsoleMode(stdin_handle, in_mode);
|
||||
SetConsoleMode(stdout_handle, out_mode);
|
||||
#else
|
||||
struct termios terminal;
|
||||
struct termios terminal; // NOLINT
|
||||
tcgetattr(STDIN_FILENO, &terminal);
|
||||
on_exit_functions.push([=] { tcsetattr(STDIN_FILENO, TCSANOW, &terminal); });
|
||||
|
||||
terminal.c_lflag &= ~ICANON; // Non canonique terminal.
|
||||
terminal.c_lflag &= ~ECHO; // Do not print after a key press.
|
||||
terminal.c_lflag &= ~ICANON; // NOLINT Non canonique terminal.
|
||||
terminal.c_lflag &= ~ECHO; // NOLINT Do not print after a key press.
|
||||
terminal.c_cc[VMIN] = 0;
|
||||
terminal.c_cc[VTIME] = 0;
|
||||
// auto oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
@@ -420,19 +435,19 @@ void ScreenInteractive::Install() {
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &terminal);
|
||||
|
||||
// Handle resize.
|
||||
on_resize = [&] { task_sender_->Send(Event::Special({0})); };
|
||||
g_on_resize = [&] { task_sender_->Send(Event::Special({0})); };
|
||||
install_signal_handler(SIGWINCH, OnResize);
|
||||
|
||||
// Handle SIGTSTP/SIGCONT.
|
||||
install_signal_handler(SIGTSTP, OnSigStop);
|
||||
#endif
|
||||
|
||||
auto enable = [&](std::vector<DECMode> parameters) {
|
||||
auto enable = [&](const std::vector<DECMode>& parameters) {
|
||||
std::cout << Set(parameters);
|
||||
on_exit_functions.push([=] { std::cout << Reset(parameters); });
|
||||
};
|
||||
|
||||
auto disable = [&](std::vector<DECMode> parameters) {
|
||||
auto disable = [&](const std::vector<DECMode>& parameters) {
|
||||
std::cout << Reset(parameters);
|
||||
on_exit_functions.push([=] { std::cout << Set(parameters); });
|
||||
};
|
||||
@@ -475,6 +490,7 @@ void ScreenInteractive::Uninstall() {
|
||||
OnExit(0);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
void ScreenInteractive::Main(Component component) {
|
||||
previous_animation_time = animation::Clock::now();
|
||||
|
||||
@@ -493,8 +509,9 @@ void ScreenInteractive::Main(Component component) {
|
||||
}
|
||||
|
||||
Task task;
|
||||
if (!task_receiver_->Receive(&task))
|
||||
if (!task_receiver_->Receive(&task)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
std::visit([&](auto&& arg) {
|
||||
@@ -527,8 +544,9 @@ void ScreenInteractive::Main(Component component) {
|
||||
|
||||
// Handle Animation
|
||||
if constexpr (std::is_same_v<T, AnimationTask>) {
|
||||
if (!animation_requested_)
|
||||
if (!animation_requested_) {
|
||||
return;
|
||||
}
|
||||
|
||||
animation_requested_ = false;
|
||||
animation::TimePoint now = animation::Clock::now();
|
||||
@@ -546,6 +564,7 @@ void ScreenInteractive::Main(Component component) {
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
void ScreenInteractive::Draw(Component component) {
|
||||
auto document = component->Render();
|
||||
int dimx = 0;
|
||||
@@ -596,13 +615,16 @@ void ScreenInteractive::Draw(Component component) {
|
||||
// https://github.com/ArthurSonzogni/FTXUI/issues/136
|
||||
static int i = -3;
|
||||
++i;
|
||||
if (!use_alternative_screen_ && (i % 150 == 0))
|
||||
if (!use_alternative_screen_ && (i % 150 == 0)) { // NOLINT
|
||||
std::cout << DeviceStatusReport(DSRMode::kCursor);
|
||||
}
|
||||
#else
|
||||
static int i = -3;
|
||||
++i;
|
||||
if (!use_alternative_screen_ && (previous_frame_resized_ || i % 40 == 0))
|
||||
if (!use_alternative_screen_ &&
|
||||
(previous_frame_resized_ || i % 40 == 0)) { // NOLINT
|
||||
std::cout << DeviceStatusReport(DSRMode::kCursor);
|
||||
}
|
||||
#endif
|
||||
previous_frame_resized_ = resized;
|
||||
|
||||
|
@@ -18,13 +18,13 @@ template <class T>
|
||||
class SliderBase : public ComponentBase {
|
||||
public:
|
||||
SliderBase(ConstStringRef label, T* value, T min, T max, T increment)
|
||||
: label_(label),
|
||||
: label_(std::move(label)),
|
||||
value_(value),
|
||||
min_(min),
|
||||
max_(max),
|
||||
increment_(increment) {}
|
||||
|
||||
Element Render() {
|
||||
Element Render() override {
|
||||
auto gauge_color =
|
||||
Focused() ? color(Color::GrayLight) : color(Color::GrayDark);
|
||||
float percent = float(*value_ - min_) / float(max_ - min_);
|
||||
@@ -40,8 +40,9 @@ class SliderBase : public ComponentBase {
|
||||
}
|
||||
|
||||
bool OnEvent(Event event) final {
|
||||
if (event.is_mouse())
|
||||
if (event.is_mouse()) {
|
||||
return OnMouseEvent(event);
|
||||
}
|
||||
|
||||
if (event == Event::ArrowLeft || event == Event::Character('h')) {
|
||||
*value_ -= increment_;
|
||||
|
@@ -14,11 +14,14 @@ TerminalInputParser::TerminalInputParser(Sender<Task> out)
|
||||
|
||||
void TerminalInputParser::Timeout(int time) {
|
||||
timeout_ += time;
|
||||
if (timeout_ < 50)
|
||||
const int timeout_threshold = 50;
|
||||
if (timeout_ < timeout_threshold) {
|
||||
return;
|
||||
}
|
||||
timeout_ = 0;
|
||||
if (pending_.size())
|
||||
if (!pending_.empty()) {
|
||||
Send(SPECIAL);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalInputParser::Add(char c) {
|
||||
@@ -56,21 +59,23 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) {
|
||||
// key. This also happens with linux with the `bind` command:
|
||||
// See https://github.com/ArthurSonzogni/FTXUI/issues/337
|
||||
// Here, we uniformize the new line character to `\n`.
|
||||
if (pending_ == "\r")
|
||||
if (pending_ == "\r") {
|
||||
out_->Send(Event::Special("\n"));
|
||||
else
|
||||
} else {
|
||||
out_->Send(Event::Special(std::move(pending_)));
|
||||
}
|
||||
pending_.clear();
|
||||
return;
|
||||
|
||||
case MOUSE:
|
||||
out_->Send(Event::Mouse(std::move(pending_), output.mouse));
|
||||
out_->Send(Event::Mouse(std::move(pending_), output.mouse)); // NOLINT
|
||||
pending_.clear();
|
||||
return;
|
||||
|
||||
case CURSOR_REPORTING:
|
||||
out_->Send(Event::CursorReporting(std::move(pending_), output.cursor.x,
|
||||
output.cursor.y));
|
||||
out_->Send(Event::CursorReporting(std::move(pending_), // NOLINT
|
||||
output.cursor.x, // NOLINT
|
||||
output.cursor.y)); // NOLINT
|
||||
pending_.clear();
|
||||
return;
|
||||
}
|
||||
@@ -78,12 +83,13 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) {
|
||||
}
|
||||
|
||||
TerminalInputParser::Output TerminalInputParser::Parse() {
|
||||
if (!Eat())
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
}
|
||||
|
||||
switch (Current()) {
|
||||
case 24: // CAN
|
||||
case 26: // SUB
|
||||
case 24: // CAN NOLINT
|
||||
case 26: // SUB NOLINT
|
||||
return DROP;
|
||||
|
||||
case '\x1B':
|
||||
@@ -92,11 +98,13 @@ TerminalInputParser::Output TerminalInputParser::Parse() {
|
||||
break;
|
||||
}
|
||||
|
||||
if (Current() < 32) // C0
|
||||
if (Current() < 32) { // C0 NOLINT
|
||||
return SPECIAL;
|
||||
}
|
||||
|
||||
if (Current() == 127) // Delete
|
||||
if (Current() == 127) { // Delete // NOLINT
|
||||
return SPECIAL;
|
||||
}
|
||||
|
||||
return ParseUTF8();
|
||||
}
|
||||
@@ -118,18 +126,18 @@ TerminalInputParser::Output TerminalInputParser::Parse() {
|
||||
// Then some sequences are illegal if it exist a shorter representation of the
|
||||
// same codepoint.
|
||||
TerminalInputParser::Output TerminalInputParser::ParseUTF8() {
|
||||
unsigned char head = static_cast<unsigned char>(Current());
|
||||
unsigned char selector = 0b1000'0000;
|
||||
auto head = static_cast<unsigned char>(Current());
|
||||
unsigned char selector = 0b1000'0000; // NOLINT
|
||||
|
||||
// The non code-point part of the first byte.
|
||||
unsigned char mask = selector;
|
||||
|
||||
// Find the first zero in the first byte.
|
||||
int first_zero = 8;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
unsigned int first_zero = 8; // NOLINT
|
||||
for (unsigned int i = 0; i < 8; ++i) { // NOLINT
|
||||
mask |= selector;
|
||||
if (head & selector) {
|
||||
selector >>= 1;
|
||||
selector >>= 1U;
|
||||
continue;
|
||||
}
|
||||
first_zero = i;
|
||||
@@ -137,48 +145,54 @@ TerminalInputParser::Output TerminalInputParser::ParseUTF8() {
|
||||
}
|
||||
|
||||
// Accumulate the value of the first byte.
|
||||
uint32_t value = head & ~mask;
|
||||
auto value = uint32_t(head & ~mask); // NOLINT
|
||||
|
||||
// Invalid UTF8, with more than 5 bytes.
|
||||
if (first_zero == 1 || first_zero >= 5)
|
||||
const unsigned int max_utf8_bytes = 5;
|
||||
if (first_zero == 1 || first_zero >= max_utf8_bytes) {
|
||||
return DROP;
|
||||
}
|
||||
|
||||
// Multi byte UTF-8.
|
||||
for (int i = 2; i <= first_zero; ++i) {
|
||||
if (!Eat())
|
||||
for (unsigned int i = 2; i <= first_zero; ++i) {
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
}
|
||||
|
||||
// Invalid continuation byte.
|
||||
head = static_cast<unsigned char>(Current());
|
||||
if ((head & 0b1100'0000) != 0b1000'0000)
|
||||
if ((head & 0b1100'0000) != 0b1000'0000) { // NOLINT
|
||||
return DROP;
|
||||
value <<= 6;
|
||||
value += head & 0b0011'1111;
|
||||
}
|
||||
value <<= 6; // NOLINT
|
||||
value += head & 0b0011'1111; // NOLINT
|
||||
}
|
||||
|
||||
// Check for overlong UTF8 encoding.
|
||||
int extra_byte;
|
||||
if (value <= 0b000'0000'0111'1111) {
|
||||
extra_byte = 0;
|
||||
} else if (value <= 0b000'0111'1111'1111) {
|
||||
extra_byte = 1;
|
||||
} else if (value <= 0b1111'1111'1111'1111) {
|
||||
extra_byte = 2;
|
||||
} else if (value <= 0b1'0000'1111'1111'1111'1111) {
|
||||
extra_byte = 3;
|
||||
} else {
|
||||
int extra_byte = 0;
|
||||
if (value <= 0b000'0000'0111'1111) { // NOLINT
|
||||
extra_byte = 0; // NOLINT
|
||||
} else if (value <= 0b000'0111'1111'1111) { // NOLINT
|
||||
extra_byte = 1; // NOLINT
|
||||
} else if (value <= 0b1111'1111'1111'1111) { // NOLINT
|
||||
extra_byte = 2; // NOLINT
|
||||
} else if (value <= 0b1'0000'1111'1111'1111'1111) { // NOLINT
|
||||
extra_byte = 3; // NOLINT
|
||||
} else { // NOLINT
|
||||
return DROP;
|
||||
}
|
||||
|
||||
if (extra_byte != position_)
|
||||
if (extra_byte != position_) {
|
||||
return DROP;
|
||||
}
|
||||
|
||||
return CHARACTER;
|
||||
}
|
||||
|
||||
TerminalInputParser::Output TerminalInputParser::ParseESC() {
|
||||
if (!Eat())
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
}
|
||||
switch (Current()) {
|
||||
case 'P':
|
||||
return ParseDCS();
|
||||
@@ -187,26 +201,32 @@ TerminalInputParser::Output TerminalInputParser::ParseESC() {
|
||||
case ']':
|
||||
return ParseOSC();
|
||||
default:
|
||||
if (!Eat())
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
return SPECIAL;
|
||||
} else {
|
||||
return SPECIAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TerminalInputParser::Output TerminalInputParser::ParseDCS() {
|
||||
// Parse until the string terminator ST.
|
||||
while (1) {
|
||||
if (!Eat())
|
||||
while (true) {
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
}
|
||||
|
||||
if (Current() != '\x1B')
|
||||
if (Current() != '\x1B') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Eat())
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
}
|
||||
|
||||
if (Current() != '\\')
|
||||
if (Current() != '\\') {
|
||||
continue;
|
||||
}
|
||||
|
||||
return SPECIAL;
|
||||
}
|
||||
@@ -217,8 +237,9 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() {
|
||||
int argument = 0;
|
||||
std::vector<int> arguments;
|
||||
while (true) {
|
||||
if (!Eat())
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
}
|
||||
|
||||
if (Current() == '<') {
|
||||
altered = true;
|
||||
@@ -226,7 +247,7 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() {
|
||||
}
|
||||
|
||||
if (Current() >= '0' && Current() <= '9') {
|
||||
argument *= 10;
|
||||
argument *= 10; // NOLINT
|
||||
argument += int(Current() - '0');
|
||||
continue;
|
||||
}
|
||||
@@ -239,7 +260,7 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() {
|
||||
|
||||
if (Current() >= ' ' && Current() <= '~' && Current() != '<') {
|
||||
arguments.push_back(argument);
|
||||
argument = 0;
|
||||
argument = 0; // NOLINT
|
||||
switch (Current()) {
|
||||
case 'M':
|
||||
return ParseMouse(altered, true, std::move(arguments));
|
||||
@@ -253,53 +274,61 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() {
|
||||
}
|
||||
|
||||
// Invalid ESC in CSI.
|
||||
if (Current() == '\x1B')
|
||||
if (Current() == '\x1B') {
|
||||
return SPECIAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TerminalInputParser::Output TerminalInputParser::ParseOSC() {
|
||||
// Parse until the string terminator ST.
|
||||
while (true) {
|
||||
if (!Eat())
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
if (Current() != '\x1B')
|
||||
}
|
||||
if (Current() != '\x1B') {
|
||||
continue;
|
||||
if (!Eat())
|
||||
}
|
||||
if (!Eat()) {
|
||||
return UNCOMPLETED;
|
||||
if (Current() != '\\')
|
||||
}
|
||||
if (Current() != '\\') {
|
||||
continue;
|
||||
}
|
||||
return SPECIAL;
|
||||
}
|
||||
}
|
||||
|
||||
TerminalInputParser::Output TerminalInputParser::ParseMouse(
|
||||
TerminalInputParser::Output TerminalInputParser::ParseMouse( // NOLINT
|
||||
bool altered,
|
||||
bool pressed,
|
||||
std::vector<int> arguments) {
|
||||
if (arguments.size() != 3)
|
||||
if (arguments.size() != 3) {
|
||||
return SPECIAL;
|
||||
}
|
||||
|
||||
(void)altered;
|
||||
|
||||
Output output(MOUSE);
|
||||
output.mouse.button = Mouse::Button((arguments[0] & 3) + //
|
||||
((arguments[0] & 64) >> 4));
|
||||
output.mouse.motion = Mouse::Motion(pressed);
|
||||
output.mouse.shift = bool(arguments[0] & 4);
|
||||
output.mouse.meta = bool(arguments[0] & 8);
|
||||
output.mouse.x = arguments[1];
|
||||
output.mouse.y = arguments[2];
|
||||
output.mouse.button = Mouse::Button((arguments[0] & 3) + // NOLINT
|
||||
((arguments[0] & 64) >> 4)); // NOLINT
|
||||
output.mouse.motion = Mouse::Motion(pressed); // NOLINT
|
||||
output.mouse.shift = bool(arguments[0] & 4); // NOLINT
|
||||
output.mouse.meta = bool(arguments[0] & 8); // NOLINT
|
||||
output.mouse.x = arguments[1]; // NOLINT
|
||||
output.mouse.y = arguments[2]; // NOLINT
|
||||
return output;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
TerminalInputParser::Output TerminalInputParser::ParseCursorReporting(
|
||||
std::vector<int> arguments) {
|
||||
if (arguments.size() != 2)
|
||||
if (arguments.size() != 2) {
|
||||
return SPECIAL;
|
||||
}
|
||||
Output output(CURSOR_REPORTING);
|
||||
output.cursor.y = arguments[0];
|
||||
output.cursor.x = arguments[1];
|
||||
output.cursor.y = arguments[0]; // NOLINT
|
||||
output.cursor.x = arguments[1]; // NOLINT
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@@ -48,7 +48,7 @@ class TerminalInputParser {
|
||||
Output(Type t) : type(t) {}
|
||||
};
|
||||
|
||||
void Send(Output type);
|
||||
void Send(Output output);
|
||||
Output Parse();
|
||||
Output ParseUTF8();
|
||||
Output ParseESC();
|
||||
|
@@ -5,21 +5,25 @@
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
Component operator|(Component component, ComponentDecorator decorator) {
|
||||
return decorator(component);
|
||||
return decorator(component); // NOLINT
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
Component operator|(Component component, ElementDecorator decorator) {
|
||||
return component | Renderer(decorator);
|
||||
return component | Renderer(decorator); // NOLINT
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
Component& operator|=(Component& component, ComponentDecorator decorator) {
|
||||
component = component | decorator;
|
||||
component = component | decorator; // NOLINT
|
||||
return component;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
Component& operator|=(Component& component, ElementDecorator decorator) {
|
||||
component = component | decorator;
|
||||
component = component | decorator; // NOLINT
|
||||
return component;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user