Initial commit
This commit is contained in:
118
include/ftxui/component/animation.hpp
Normal file
118
include/ftxui/component/animation.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright 2022 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_ANIMATION_HPP
|
||||
#define FTXUI_ANIMATION_HPP
|
||||
|
||||
#include <chrono> // for milliseconds, duration, steady_clock, time_point
|
||||
#include <functional> // for function
|
||||
|
||||
#include "ftxui/component/event.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
namespace animation {
|
||||
// Components who haven't completed their animation can call this function to
|
||||
// request a new frame to be drawn later.
|
||||
//
|
||||
// When there is no new events and no animations to complete, no new frame is
|
||||
// drawn.
|
||||
void RequestAnimationFrame();
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using TimePoint = std::chrono::time_point<Clock>;
|
||||
using Duration = std::chrono::duration<float>;
|
||||
|
||||
// Parameter of Component::OnAnimation(param).
|
||||
class Params {
|
||||
public:
|
||||
Params(Duration duration) : duration_(duration) {}
|
||||
|
||||
/// The duration this animation step represents.
|
||||
Duration duration() const { return duration_; }
|
||||
|
||||
private:
|
||||
Duration duration_;
|
||||
};
|
||||
|
||||
namespace easing {
|
||||
using Function = std::function<float(float)>;
|
||||
// Linear interpolation (no easing)
|
||||
float Linear(float p);
|
||||
|
||||
// Quadratic easing; p^2
|
||||
float QuadraticIn(float p);
|
||||
float QuadraticOut(float p);
|
||||
float QuadraticInOut(float p);
|
||||
|
||||
// Cubic easing; p^3
|
||||
float CubicIn(float p);
|
||||
float CubicOut(float p);
|
||||
float CubicInOut(float p);
|
||||
|
||||
// Quartic easing; p^4
|
||||
float QuarticIn(float p);
|
||||
float QuarticOut(float p);
|
||||
float QuarticInOut(float p);
|
||||
|
||||
// Quintic easing; p^5
|
||||
float QuinticIn(float p);
|
||||
float QuinticOut(float p);
|
||||
float QuinticInOut(float p);
|
||||
|
||||
// Sine wave easing; sin(p * PI/2)
|
||||
float SineIn(float p);
|
||||
float SineOut(float p);
|
||||
float SineInOut(float p);
|
||||
|
||||
// Circular easing; sqrt(1 - p^2)
|
||||
float CircularIn(float p);
|
||||
float CircularOut(float p);
|
||||
float CircularInOut(float p);
|
||||
|
||||
// Exponential easing, base 2
|
||||
float ExponentialIn(float p);
|
||||
float ExponentialOut(float p);
|
||||
float ExponentialInOut(float p);
|
||||
|
||||
// Exponentially-damped sine wave easing
|
||||
float ElasticIn(float p);
|
||||
float ElasticOut(float p);
|
||||
float ElasticInOut(float p);
|
||||
|
||||
// Overshooting cubic easing;
|
||||
float BackIn(float p);
|
||||
float BackOut(float p);
|
||||
float BackInOut(float p);
|
||||
|
||||
// Exponentially-decaying bounce easing
|
||||
float BounceIn(float p);
|
||||
float BounceOut(float p);
|
||||
float BounceInOut(float p);
|
||||
} // namespace easing
|
||||
|
||||
class Animator {
|
||||
public:
|
||||
Animator(float* from,
|
||||
float to = 0.f,
|
||||
Duration duration = std::chrono::milliseconds(250),
|
||||
easing::Function easing_function = easing::Linear,
|
||||
Duration delay = std::chrono::milliseconds(0));
|
||||
|
||||
void OnAnimation(Params&);
|
||||
|
||||
float to() const { return to_; }
|
||||
|
||||
private:
|
||||
float* value_;
|
||||
float from_;
|
||||
float to_;
|
||||
Duration duration_;
|
||||
easing::Function easing_function_;
|
||||
Duration current_;
|
||||
};
|
||||
|
||||
} // namespace animation
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_ANIMATION_HPP */
|
||||
17
include/ftxui/component/captured_mouse.hpp
Normal file
17
include/ftxui/component/captured_mouse.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_CAPTURED_MOUSE_HPP
|
||||
#define FTXUI_CAPTURED_MOUSE_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ftxui {
|
||||
class CapturedMouseInterface {
|
||||
public:
|
||||
virtual ~CapturedMouseInterface() = default;
|
||||
};
|
||||
using CapturedMouse = std::unique_ptr<CapturedMouseInterface>;
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_CAPTURED_MOUSE_HPP */
|
||||
142
include/ftxui/component/component.hpp
Normal file
142
include/ftxui/component/component.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_HPP
|
||||
#define FTXUI_COMPONENT_HPP
|
||||
|
||||
#include <functional> // for function
|
||||
#include <memory> // for make_shared, shared_ptr
|
||||
#include <string> // for wstring
|
||||
#include <utility> // for forward
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/component_base.hpp" // for Component, Components
|
||||
#include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, MenuOption
|
||||
#include "ftxui/dom/elements.hpp" // for Element
|
||||
#include "ftxui/util/ref.hpp" // for ConstRef, Ref, ConstStringRef, ConstStringListRef, StringRef
|
||||
|
||||
namespace ftxui {
|
||||
struct ButtonOption;
|
||||
struct CheckboxOption;
|
||||
struct Event;
|
||||
struct InputOption;
|
||||
struct MenuOption;
|
||||
struct RadioboxOption;
|
||||
struct MenuEntryOption;
|
||||
|
||||
template <class T, class... Args>
|
||||
std::shared_ptr<T> Make(Args&&... args) {
|
||||
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Pipe operator to decorate components.
|
||||
using ComponentDecorator = std::function<Component(Component)>;
|
||||
using ElementDecorator = std::function<Element(Element)>;
|
||||
Component operator|(Component component, ComponentDecorator decorator);
|
||||
Component operator|(Component component, ElementDecorator decorator);
|
||||
Component& operator|=(Component& component, ComponentDecorator decorator);
|
||||
Component& operator|=(Component& component, ElementDecorator decorator);
|
||||
|
||||
namespace Container {
|
||||
Component Vertical(Components children);
|
||||
Component Vertical(Components children, int* selector);
|
||||
Component Horizontal(Components children);
|
||||
Component Horizontal(Components children, int* selector);
|
||||
Component Tab(Components children, int* selector);
|
||||
Component Stacked(Components children);
|
||||
} // namespace Container
|
||||
|
||||
Component Button(ButtonOption options);
|
||||
Component Button(ConstStringRef label,
|
||||
std::function<void()> on_click,
|
||||
ButtonOption options = ButtonOption::Simple());
|
||||
|
||||
Component Checkbox(CheckboxOption options);
|
||||
Component Checkbox(ConstStringRef label,
|
||||
bool* checked,
|
||||
CheckboxOption options = CheckboxOption::Simple());
|
||||
|
||||
Component Input(InputOption options = {});
|
||||
Component Input(StringRef content, InputOption options = {});
|
||||
Component Input(StringRef content,
|
||||
StringRef placeholder,
|
||||
InputOption options = {});
|
||||
|
||||
Component Menu(MenuOption options);
|
||||
Component Menu(ConstStringListRef entries,
|
||||
int* selected_,
|
||||
MenuOption options = MenuOption::Vertical());
|
||||
Component MenuEntry(MenuEntryOption options);
|
||||
Component MenuEntry(ConstStringRef label, MenuEntryOption options = {});
|
||||
|
||||
Component Radiobox(RadioboxOption options);
|
||||
Component Radiobox(ConstStringListRef entries,
|
||||
int* selected_,
|
||||
RadioboxOption options = {});
|
||||
|
||||
Component Dropdown(ConstStringListRef entries, int* selected);
|
||||
Component Toggle(ConstStringListRef entries, int* selected);
|
||||
|
||||
// General slider constructor:
|
||||
template <typename T>
|
||||
Component Slider(SliderOption<T> options);
|
||||
|
||||
// Shorthand without the `SliderOption` constructor:
|
||||
Component Slider(ConstStringRef label,
|
||||
Ref<int> value,
|
||||
ConstRef<int> min = 0,
|
||||
ConstRef<int> max = 100,
|
||||
ConstRef<int> increment = 5);
|
||||
Component Slider(ConstStringRef label,
|
||||
Ref<float> value,
|
||||
ConstRef<float> min = 0.f,
|
||||
ConstRef<float> max = 100.f,
|
||||
ConstRef<float> increment = 5.f);
|
||||
Component Slider(ConstStringRef label,
|
||||
Ref<long> value,
|
||||
ConstRef<long> min = 0l,
|
||||
ConstRef<long> max = 100l,
|
||||
ConstRef<long> increment = 5l);
|
||||
|
||||
Component ResizableSplit(ResizableSplitOption options);
|
||||
Component ResizableSplitLeft(Component main, Component back, int* main_size);
|
||||
Component ResizableSplitRight(Component main, Component back, int* main_size);
|
||||
Component ResizableSplitTop(Component main, Component back, int* main_size);
|
||||
Component ResizableSplitBottom(Component main, Component back, int* main_size);
|
||||
|
||||
Component Renderer(Component child, std::function<Element()>);
|
||||
Component Renderer(std::function<Element()>);
|
||||
Component Renderer(std::function<Element(bool /* focused */)>);
|
||||
ComponentDecorator Renderer(ElementDecorator);
|
||||
|
||||
Component CatchEvent(Component child, std::function<bool(Event)>);
|
||||
ComponentDecorator CatchEvent(std::function<bool(Event)> on_event);
|
||||
|
||||
Component Maybe(Component, const bool* show);
|
||||
Component Maybe(Component, std::function<bool()>);
|
||||
ComponentDecorator Maybe(const bool* show);
|
||||
ComponentDecorator Maybe(std::function<bool()>);
|
||||
|
||||
Component Modal(Component main, Component modal, const bool* show_modal);
|
||||
ComponentDecorator Modal(Component modal, const bool* show_modal);
|
||||
|
||||
Component Collapsible(ConstStringRef label,
|
||||
Component child,
|
||||
Ref<bool> show = false);
|
||||
|
||||
Component Hoverable(Component component, bool* hover);
|
||||
Component Hoverable(Component component,
|
||||
std::function<void()> on_enter,
|
||||
std::function<void()> on_leave);
|
||||
Component Hoverable(Component component, //
|
||||
std::function<void(bool)> on_change);
|
||||
ComponentDecorator Hoverable(bool* hover);
|
||||
ComponentDecorator Hoverable(std::function<void()> on_enter,
|
||||
std::function<void()> on_leave);
|
||||
ComponentDecorator Hoverable(std::function<void(bool)> on_change);
|
||||
|
||||
Component Window(WindowOptions option);
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_HPP */
|
||||
98
include/ftxui/component/component_base.hpp
Normal file
98
include/ftxui/component/component_base.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_BASE_HPP
|
||||
#define FTXUI_COMPONENT_BASE_HPP
|
||||
|
||||
#include <memory> // for unique_ptr
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CaptureMouse
|
||||
#include "ftxui/dom/elements.hpp" // for Element
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
class Delegate;
|
||||
class Focus;
|
||||
struct Event;
|
||||
|
||||
namespace animation {
|
||||
class Params;
|
||||
} // namespace animation
|
||||
|
||||
class ComponentBase;
|
||||
using Component = std::shared_ptr<ComponentBase>;
|
||||
using Components = std::vector<Component>;
|
||||
|
||||
/// @brief It implement rendering itself as ftxui::Element. It implement
|
||||
/// keyboard navigation by responding to ftxui::Event.
|
||||
/// @ingroup component
|
||||
class ComponentBase {
|
||||
public:
|
||||
// virtual Destructor.
|
||||
virtual ~ComponentBase();
|
||||
|
||||
ComponentBase() = default;
|
||||
|
||||
// A component is not copiable.
|
||||
ComponentBase(const ComponentBase&) = delete;
|
||||
void operator=(const ComponentBase&) = delete;
|
||||
|
||||
// Component hierarchy:
|
||||
ComponentBase* Parent() const;
|
||||
Component& ChildAt(size_t i);
|
||||
size_t ChildCount() const;
|
||||
void Add(Component children);
|
||||
void Detach();
|
||||
void DetachAllChildren();
|
||||
|
||||
// Renders the component.
|
||||
virtual Element Render();
|
||||
|
||||
// Handles an event.
|
||||
// By default, reduce on children with a lazy OR.
|
||||
//
|
||||
// Returns whether the event was handled or not.
|
||||
virtual bool OnEvent(Event);
|
||||
|
||||
// Handle an animation step.
|
||||
virtual void OnAnimation(animation::Params& params);
|
||||
|
||||
// Focus management ----------------------------------------------------------
|
||||
//
|
||||
// If this component contains children, this indicates which one is active,
|
||||
// nullptr if none is active.
|
||||
//
|
||||
// We say an element has the focus if the chain of ActiveChild() from the
|
||||
// root component contains this object.
|
||||
virtual Component ActiveChild();
|
||||
|
||||
// Return true when the component contains focusable elements.
|
||||
// The non focusable Component will be skipped when navigating using the
|
||||
// keyboard.
|
||||
virtual bool Focusable() const;
|
||||
|
||||
// Whether this is the active child of its parent.
|
||||
bool Active() const;
|
||||
// Whether all the ancestors are active.
|
||||
bool Focused() const;
|
||||
|
||||
// Make the |child| to be the "active" one.
|
||||
virtual void SetActiveChild(ComponentBase* child);
|
||||
void SetActiveChild(Component child);
|
||||
|
||||
// Configure all the ancestors to give focus to this component.
|
||||
void TakeFocus();
|
||||
|
||||
protected:
|
||||
CapturedMouse CaptureMouse(const Event& event);
|
||||
|
||||
Components children_;
|
||||
|
||||
private:
|
||||
ComponentBase* parent_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_BASE_HPP */
|
||||
267
include/ftxui/component/component_options.hpp
Normal file
267
include/ftxui/component/component_options.hpp
Normal file
@@ -0,0 +1,267 @@
|
||||
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP
|
||||
#define FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP
|
||||
|
||||
#include <chrono> // for milliseconds
|
||||
#include <ftxui/component/animation.hpp> // for Duration, QuadraticInOut, Function
|
||||
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Left, Direction::Right, Direction::Down
|
||||
#include <ftxui/dom/elements.hpp> // for Element, separator
|
||||
#include <ftxui/util/ref.hpp> // for Ref, ConstRef, StringRef
|
||||
#include <functional> // for function
|
||||
#include <optional> // for optional
|
||||
#include <string> // for string
|
||||
|
||||
#include "ftxui/component/component_base.hpp" // for Component
|
||||
#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
/// @brief arguments for |ButtonOption::transform|, |CheckboxOption::transform|,
|
||||
/// |Radiobox::transform|, |MenuEntryOption::transform|,
|
||||
/// |MenuOption::transform|.
|
||||
struct EntryState {
|
||||
std::string label; /// < The label to display.
|
||||
bool state; /// < The state of the button/checkbox/radiobox
|
||||
bool active; /// < Whether the entry is the active one.
|
||||
bool focused; /// < Whether the entry is one focused by the user.
|
||||
};
|
||||
|
||||
struct UnderlineOption {
|
||||
bool enabled = false;
|
||||
|
||||
Color color_active = Color::White;
|
||||
Color color_inactive = Color::GrayDark;
|
||||
|
||||
animation::easing::Function leader_function =
|
||||
animation::easing::QuadraticInOut;
|
||||
animation::easing::Function follower_function =
|
||||
animation::easing::QuadraticInOut;
|
||||
|
||||
animation::Duration leader_duration = std::chrono::milliseconds(250);
|
||||
animation::Duration leader_delay = std::chrono::milliseconds(0);
|
||||
animation::Duration follower_duration = std::chrono::milliseconds(250);
|
||||
animation::Duration follower_delay = std::chrono::milliseconds(0);
|
||||
|
||||
void SetAnimation(animation::Duration d, animation::easing::Function f);
|
||||
void SetAnimationDuration(animation::Duration d);
|
||||
void SetAnimationFunction(animation::easing::Function f);
|
||||
void SetAnimationFunction(animation::easing::Function f_leader,
|
||||
animation::easing::Function f_follower);
|
||||
};
|
||||
|
||||
/// @brief Option about a potentially animated color.
|
||||
/// @ingroup component
|
||||
struct AnimatedColorOption {
|
||||
void Set(
|
||||
Color inactive,
|
||||
Color active,
|
||||
animation::Duration duration = std::chrono::milliseconds(250),
|
||||
animation::easing::Function function = animation::easing::QuadraticInOut);
|
||||
|
||||
bool enabled = false;
|
||||
Color inactive;
|
||||
Color active;
|
||||
animation::Duration duration = std::chrono::milliseconds(250);
|
||||
animation::easing::Function function = animation::easing::QuadraticInOut;
|
||||
};
|
||||
|
||||
struct AnimatedColorsOption {
|
||||
AnimatedColorOption background;
|
||||
AnimatedColorOption foreground;
|
||||
};
|
||||
|
||||
/// @brief Option for the MenuEntry component.
|
||||
/// @ingroup component
|
||||
struct MenuEntryOption {
|
||||
ConstStringRef label = "MenuEntry";
|
||||
std::function<Element(const EntryState& state)> transform;
|
||||
AnimatedColorsOption animated_colors;
|
||||
};
|
||||
|
||||
/// @brief Option for the Menu component.
|
||||
/// @ingroup component
|
||||
struct MenuOption {
|
||||
// Standard constructors:
|
||||
static MenuOption Horizontal();
|
||||
static MenuOption HorizontalAnimated();
|
||||
static MenuOption Vertical();
|
||||
static MenuOption VerticalAnimated();
|
||||
static MenuOption Toggle();
|
||||
|
||||
ConstStringListRef entries; ///> The list of entries.
|
||||
Ref<int> selected = 0; ///> The index of the selected entry.
|
||||
|
||||
// Style:
|
||||
UnderlineOption underline;
|
||||
MenuEntryOption entries_option;
|
||||
Direction direction = Direction::Down;
|
||||
std::function<Element()> elements_prefix;
|
||||
std::function<Element()> elements_infix;
|
||||
std::function<Element()> elements_postfix;
|
||||
|
||||
// Observers:
|
||||
std::function<void()> on_change; ///> Called when the selected entry changes.
|
||||
std::function<void()> on_enter; ///> Called when the user presses enter.
|
||||
Ref<int> focused_entry = 0;
|
||||
};
|
||||
|
||||
/// @brief Option for the AnimatedButton component.
|
||||
/// @ingroup component
|
||||
struct ButtonOption {
|
||||
// Standard constructors:
|
||||
static ButtonOption Ascii();
|
||||
static ButtonOption Simple();
|
||||
static ButtonOption Border();
|
||||
static ButtonOption Animated();
|
||||
static ButtonOption Animated(Color color);
|
||||
static ButtonOption Animated(Color background, Color foreground);
|
||||
static ButtonOption Animated(Color background,
|
||||
Color foreground,
|
||||
Color background_active,
|
||||
Color foreground_active);
|
||||
|
||||
ConstStringRef label = "Button";
|
||||
std::function<void()> on_click = [] {};
|
||||
|
||||
// Style:
|
||||
std::function<Element(const EntryState&)> transform;
|
||||
AnimatedColorsOption animated_colors;
|
||||
};
|
||||
|
||||
/// @brief Option for the Checkbox component.
|
||||
/// @ingroup component
|
||||
struct CheckboxOption {
|
||||
// Standard constructors:
|
||||
static CheckboxOption Simple();
|
||||
|
||||
ConstStringRef label = "Checkbox";
|
||||
|
||||
Ref<bool> checked = false;
|
||||
|
||||
// Style:
|
||||
std::function<Element(const EntryState&)> transform;
|
||||
|
||||
// Observer:
|
||||
/// Called when the user change the state.
|
||||
std::function<void()> on_change = [] {};
|
||||
};
|
||||
|
||||
/// @brief Used to define style for the Input component.
|
||||
struct InputState {
|
||||
Element element;
|
||||
bool hovered; /// < Whether the input is hovered by the mouse.
|
||||
bool focused; /// < Whether the input is focused by the user.
|
||||
bool is_placeholder; /// < Whether the input is empty and displaying the
|
||||
/// < placeholder.
|
||||
};
|
||||
|
||||
/// @brief Option for the Input component.
|
||||
/// @ingroup component
|
||||
struct InputOption {
|
||||
// A set of predefined styles:
|
||||
|
||||
/// @brief Create the default input style:
|
||||
static InputOption Default();
|
||||
/// @brief A white on black style with high margins:
|
||||
static InputOption Spacious();
|
||||
|
||||
/// The content of the input.
|
||||
StringRef content = "";
|
||||
|
||||
/// The content of the input when it's empty.
|
||||
StringRef placeholder = "";
|
||||
|
||||
// Style:
|
||||
std::function<Element(InputState)> transform;
|
||||
Ref<bool> password = false; /// < Obscure the input content using '*'.
|
||||
Ref<bool> multiline = true; /// < Whether the input can be multiline.
|
||||
|
||||
/// Called when the content changes.
|
||||
std::function<void()> on_change = [] {};
|
||||
/// Called when the user presses enter.
|
||||
std::function<void()> on_enter = [] {};
|
||||
|
||||
// The char position of the cursor:
|
||||
Ref<int> cursor_position = 0;
|
||||
};
|
||||
|
||||
/// @brief Option for the Radiobox component.
|
||||
/// @ingroup component
|
||||
struct RadioboxOption {
|
||||
// Standard constructors:
|
||||
static RadioboxOption Simple();
|
||||
|
||||
// Content:
|
||||
ConstStringListRef entries;
|
||||
Ref<int> selected = 0;
|
||||
|
||||
// Style:
|
||||
std::function<Element(const EntryState&)> transform;
|
||||
|
||||
// Observers:
|
||||
/// Called when the selected entry changes.
|
||||
std::function<void()> on_change = [] {};
|
||||
Ref<int> focused_entry = 0;
|
||||
};
|
||||
|
||||
struct ResizableSplitOption {
|
||||
Component main;
|
||||
Component back;
|
||||
Ref<Direction> direction = Direction::Left;
|
||||
Ref<int> main_size =
|
||||
(direction() == Direction::Left || direction() == Direction::Right) ? 20
|
||||
: 10;
|
||||
std::function<Element()> separator_func = [] { return ::ftxui::separator(); };
|
||||
};
|
||||
|
||||
// @brief Option for the `Slider` component.
|
||||
// @ingroup component
|
||||
template <typename T>
|
||||
struct SliderOption {
|
||||
Ref<T> value;
|
||||
ConstRef<T> min = T(0);
|
||||
ConstRef<T> max = T(100);
|
||||
ConstRef<T> increment = (max() - min()) / 20;
|
||||
Direction direction = Direction::Right;
|
||||
Color color_active = Color::White;
|
||||
Color color_inactive = Color::GrayDark;
|
||||
};
|
||||
|
||||
// Parameter pack used by `WindowOptions::render`.
|
||||
struct WindowRenderState {
|
||||
Element inner; /// < The element wrapped inside this window.
|
||||
const std::string& title; /// < The title of the window.
|
||||
bool active = false; /// < Whether the window is the active one.
|
||||
bool drag = false; /// < Whether the window is being dragged.
|
||||
bool resize = false; /// < Whether the window is being resized.
|
||||
bool hover_left = false; /// < Whether the resizeable left side is hovered.
|
||||
bool hover_right = false; /// < Whether the resizeable right side is hovered.
|
||||
bool hover_top = false; /// < Whether the resizeable top side is hovered.
|
||||
bool hover_down = false; /// < Whether the resizeable down side is hovered.
|
||||
};
|
||||
|
||||
// @brief Option for the `Window` component.
|
||||
// @ingroup component
|
||||
struct WindowOptions {
|
||||
Component inner; /// < The component wrapped by this window.
|
||||
ConstStringRef title = ""; /// < The title displayed by this window.
|
||||
|
||||
Ref<int> left = 0; /// < The left side position of the window.
|
||||
Ref<int> top = 0; /// < The top side position of the window.
|
||||
Ref<int> width = 20; /// < The width of the window.
|
||||
Ref<int> height = 10; /// < The height of the window.
|
||||
|
||||
Ref<bool> resize_left = true; /// < Can the left side be resized?
|
||||
Ref<bool> resize_right = true; /// < Can the right side be resized?
|
||||
Ref<bool> resize_top = true; /// < Can the top side be resized?
|
||||
Ref<bool> resize_down = true; /// < Can the down side be resized?
|
||||
|
||||
/// An optional function to customize how the window looks like:
|
||||
std::function<Element(const WindowRenderState&)> render;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP */
|
||||
112
include/ftxui/component/event.hpp
Normal file
112
include/ftxui/component/event.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_EVENT_HPP
|
||||
#define FTXUI_COMPONENT_EVENT_HPP
|
||||
|
||||
#include <ftxui/component/mouse.hpp> // for Mouse
|
||||
#include <functional>
|
||||
#include <string> // for string, operator==
|
||||
#include <vector>
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
class ScreenInteractive;
|
||||
class ComponentBase;
|
||||
|
||||
/// @brief Represent an event. It can be key press event, a terminal resize, or
|
||||
/// more ...
|
||||
///
|
||||
/// For example:
|
||||
/// - Printable character can be created using Event::Character('a').
|
||||
/// - Some special are predefined, like Event::ArrowLeft.
|
||||
/// - One can find arbitrary code for special Events using:
|
||||
/// ./example/util/print_key_press
|
||||
/// For instance, CTLR+A maps to Event::Special({1});
|
||||
///
|
||||
/// Useful documentation about xterm specification:
|
||||
/// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
struct Event {
|
||||
// --- Constructor section ---------------------------------------------------
|
||||
static Event Character(std::string);
|
||||
static Event Character(char);
|
||||
static Event Character(wchar_t);
|
||||
static Event Special(std::string);
|
||||
static Event Mouse(std::string, Mouse mouse);
|
||||
static Event CursorReporting(std::string, int x, int y);
|
||||
|
||||
// --- Arrow ---
|
||||
static const Event ArrowLeft;
|
||||
static const Event ArrowRight;
|
||||
static const Event ArrowUp;
|
||||
static const Event ArrowDown;
|
||||
|
||||
static const Event ArrowLeftCtrl;
|
||||
static const Event ArrowRightCtrl;
|
||||
static const Event ArrowUpCtrl;
|
||||
static const Event ArrowDownCtrl;
|
||||
|
||||
// --- Other ---
|
||||
static const Event Backspace;
|
||||
static const Event Delete;
|
||||
static const Event Return;
|
||||
static const Event Escape;
|
||||
static const Event Tab;
|
||||
static const Event TabReverse;
|
||||
static const Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12;
|
||||
|
||||
static const Event Home;
|
||||
static const Event End;
|
||||
|
||||
static const Event PageUp;
|
||||
static const Event PageDown;
|
||||
|
||||
// --- Custom ---
|
||||
static const Event Custom;
|
||||
|
||||
//--- Method section ---------------------------------------------------------
|
||||
bool is_character() const { return type_ == Type::Character; }
|
||||
std::string character() const { return input_; }
|
||||
|
||||
bool is_mouse() const { return type_ == Type::Mouse; }
|
||||
struct Mouse& mouse() { return data_.mouse; }
|
||||
|
||||
bool is_cursor_reporting() const { return type_ == Type::CursorReporting; }
|
||||
int cursor_x() const { return data_.cursor.x; }
|
||||
int cursor_y() const { return data_.cursor.y; }
|
||||
|
||||
const std::string& input() const { return input_; }
|
||||
|
||||
bool operator==(const Event& other) const { return input_ == other.input_; }
|
||||
bool operator!=(const Event& other) const { return !operator==(other); }
|
||||
|
||||
//--- State section ----------------------------------------------------------
|
||||
ScreenInteractive* screen_ = nullptr;
|
||||
|
||||
private:
|
||||
friend ComponentBase;
|
||||
friend ScreenInteractive;
|
||||
enum class Type {
|
||||
Unknown,
|
||||
Character,
|
||||
Mouse,
|
||||
CursorReporting,
|
||||
};
|
||||
Type type_ = Type::Unknown;
|
||||
|
||||
struct Cursor {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
|
||||
union {
|
||||
struct Mouse mouse;
|
||||
struct Cursor cursor;
|
||||
} data_ = {};
|
||||
|
||||
std::string input_;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_EVENT_HPP */
|
||||
38
include/ftxui/component/loop.hpp
Normal file
38
include/ftxui/component/loop.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2022 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_LOOP_HPP
|
||||
#define FTXUI_COMPONENT_LOOP_HPP
|
||||
|
||||
#include <memory> // for shared_ptr
|
||||
|
||||
#include "ftxui/component/component_base.hpp" // for ComponentBase
|
||||
|
||||
namespace ftxui {
|
||||
class ComponentBase;
|
||||
|
||||
using Component = std::shared_ptr<ComponentBase>;
|
||||
class ScreenInteractive;
|
||||
|
||||
class Loop {
|
||||
public:
|
||||
Loop(ScreenInteractive* screen, Component component);
|
||||
~Loop();
|
||||
|
||||
bool HasQuitted();
|
||||
void RunOnce();
|
||||
void RunOnceBlocking();
|
||||
void Run();
|
||||
|
||||
private:
|
||||
// This class is non copyable.
|
||||
Loop(const ScreenInteractive&) = delete;
|
||||
Loop& operator=(const Loop&) = delete;
|
||||
|
||||
ScreenInteractive* screen_;
|
||||
Component component_;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_COMPONENT_LOOP_HPP
|
||||
44
include/ftxui/component/mouse.hpp
Normal file
44
include/ftxui/component/mouse.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_MOUSE_HPP
|
||||
#define FTXUI_COMPONENT_MOUSE_HPP
|
||||
namespace ftxui {
|
||||
|
||||
/// @brief A mouse event. It contains the coordinate of the mouse, the button
|
||||
/// pressed and the modifier (shift, ctrl, meta).
|
||||
/// @ingroup component
|
||||
struct Mouse {
|
||||
enum Button {
|
||||
Left = 0,
|
||||
Middle = 1,
|
||||
Right = 2,
|
||||
None = 3,
|
||||
WheelUp = 4,
|
||||
WheelDown = 5,
|
||||
};
|
||||
|
||||
enum Motion {
|
||||
Released = 0,
|
||||
Pressed = 1,
|
||||
};
|
||||
|
||||
// Button
|
||||
Button button = Button::None;
|
||||
|
||||
// Motion
|
||||
Motion motion = Motion::Pressed;
|
||||
|
||||
// Modifiers:
|
||||
bool shift = false;
|
||||
bool meta = false;
|
||||
bool control = false;
|
||||
|
||||
// Coordinates:
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_MOUSE_HPP */
|
||||
140
include/ftxui/component/receiver.hpp
Normal file
140
include/ftxui/component/receiver.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_RECEIVER_HPP_
|
||||
#define FTXUI_COMPONENT_RECEIVER_HPP_
|
||||
|
||||
#include <algorithm> // for copy, max
|
||||
#include <atomic> // for atomic, __atomic_base
|
||||
#include <condition_variable> // for condition_variable
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory> // for unique_ptr, make_unique
|
||||
#include <mutex> // for mutex, unique_lock
|
||||
#include <queue> // for queue
|
||||
#include <utility> // for move
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
// Usage:
|
||||
//
|
||||
// Initialization:
|
||||
// ---------------
|
||||
//
|
||||
// auto receiver = MakeReceiver<std:string>();
|
||||
// auto sender_1= receiver->MakeSender();
|
||||
// auto sender_2 = receiver->MakeSender();
|
||||
//
|
||||
// Then move the senders elsewhere, potentially in a different thread.
|
||||
//
|
||||
// On the producer side:
|
||||
// ----------------------
|
||||
// [thread 1] sender_1->Send("hello");
|
||||
// [thread 2] sender_2->Send("world");
|
||||
//
|
||||
// On the consumer side:
|
||||
// ---------------------
|
||||
// char c;
|
||||
// while(receiver->Receive(&c)) // Return true as long as there is a producer.
|
||||
// print(c)
|
||||
//
|
||||
// Receiver::Receive() returns true when there are no more senders.
|
||||
|
||||
// clang-format off
|
||||
template<class T> class SenderImpl;
|
||||
template<class T> class ReceiverImpl;
|
||||
|
||||
template<class T> using Sender = std::unique_ptr<SenderImpl<T>>;
|
||||
template<class T> using Receiver = std::unique_ptr<ReceiverImpl<T>>;
|
||||
template<class T> Receiver<T> MakeReceiver();
|
||||
// clang-format on
|
||||
|
||||
// ---- Implementation part ----
|
||||
|
||||
template <class T>
|
||||
class SenderImpl {
|
||||
public:
|
||||
void Send(T t) { receiver_->Receive(std::move(t)); }
|
||||
~SenderImpl() { receiver_->ReleaseSender(); }
|
||||
|
||||
Sender<T> Clone() { return receiver_->MakeSender(); }
|
||||
|
||||
private:
|
||||
friend class ReceiverImpl<T>;
|
||||
SenderImpl(ReceiverImpl<T>* consumer) : receiver_(consumer) {}
|
||||
ReceiverImpl<T>* receiver_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ReceiverImpl {
|
||||
public:
|
||||
Sender<T> MakeSender() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
senders_++;
|
||||
return std::unique_ptr<SenderImpl<T>>(new SenderImpl<T>(this));
|
||||
}
|
||||
ReceiverImpl() { senders_ = 0; }
|
||||
|
||||
bool Receive(T* t) {
|
||||
while (senders_ || !queue_.empty()) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (queue_.empty())
|
||||
notifier_.wait(lock);
|
||||
if (queue_.empty())
|
||||
continue;
|
||||
*t = std::move(queue_.front());
|
||||
queue_.pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReceiveNonBlocking(T* t) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (queue_.empty())
|
||||
return false;
|
||||
*t = queue_.front();
|
||||
queue_.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasPending() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return !queue_.empty();
|
||||
}
|
||||
|
||||
bool HasQuitted() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return queue_.empty() && !senders_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class SenderImpl<T>;
|
||||
|
||||
void Receive(T t) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
queue_.push(std::move(t));
|
||||
}
|
||||
notifier_.notify_one();
|
||||
}
|
||||
|
||||
void ReleaseSender() {
|
||||
senders_--;
|
||||
notifier_.notify_one();
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::queue<T> queue_;
|
||||
std::condition_variable notifier_;
|
||||
std::atomic<int> senders_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Receiver<T> MakeReceiver() {
|
||||
return std::make_unique<ReceiverImpl<T>>();
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_COMPONENT_RECEIVER_HPP_
|
||||
127
include/ftxui/component/screen_interactive.hpp
Normal file
127
include/ftxui/component/screen_interactive.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
|
||||
#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
|
||||
|
||||
#include <atomic> // for atomic
|
||||
#include <ftxui/component/receiver.hpp> // for Receiver, Sender
|
||||
#include <functional> // for function
|
||||
#include <memory> // for shared_ptr
|
||||
#include <string> // for string
|
||||
#include <thread> // for thread
|
||||
#include <variant> // for variant
|
||||
|
||||
#include "ftxui/component/animation.hpp" // for TimePoint
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
|
||||
#include "ftxui/component/event.hpp" // for Event
|
||||
#include "ftxui/component/task.hpp" // for Task, Closure
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
|
||||
namespace ftxui {
|
||||
class ComponentBase;
|
||||
class Loop;
|
||||
struct Event;
|
||||
|
||||
using Component = std::shared_ptr<ComponentBase>;
|
||||
class ScreenInteractivePrivate;
|
||||
|
||||
class ScreenInteractive : public Screen {
|
||||
public:
|
||||
// Constructors:
|
||||
static ScreenInteractive FixedSize(int dimx, int dimy);
|
||||
static ScreenInteractive Fullscreen();
|
||||
static ScreenInteractive FitComponent();
|
||||
static ScreenInteractive TerminalOutput();
|
||||
|
||||
// Options. Must be called before Loop().
|
||||
void TrackMouse(bool enable = true);
|
||||
|
||||
// Return the currently active screen, nullptr if none.
|
||||
static ScreenInteractive* Active();
|
||||
|
||||
// Start/Stop the main loop.
|
||||
void Loop(Component);
|
||||
void Exit();
|
||||
Closure ExitLoopClosure();
|
||||
|
||||
// Post tasks to be executed by the loop.
|
||||
void Post(Task task);
|
||||
void PostEvent(Event event);
|
||||
void RequestAnimationFrame();
|
||||
|
||||
CapturedMouse CaptureMouse();
|
||||
|
||||
// Decorate a function. The outputted one will execute similarly to the
|
||||
// inputted one, but with the currently active screen terminal hooks
|
||||
// temporarily uninstalled.
|
||||
Closure WithRestoredIO(Closure);
|
||||
|
||||
private:
|
||||
void ExitNow();
|
||||
|
||||
void Install();
|
||||
void Uninstall();
|
||||
|
||||
void PreMain();
|
||||
void PostMain();
|
||||
|
||||
bool HasQuitted();
|
||||
void RunOnce(Component component);
|
||||
void RunOnceBlocking(Component component);
|
||||
|
||||
void HandleTask(Component component, Task& task);
|
||||
void Draw(Component component);
|
||||
void ResetCursorPosition();
|
||||
|
||||
void Signal(int signal);
|
||||
|
||||
ScreenInteractive* suspended_screen_ = nullptr;
|
||||
enum class Dimension {
|
||||
FitComponent,
|
||||
Fixed,
|
||||
Fullscreen,
|
||||
TerminalOutput,
|
||||
};
|
||||
Dimension dimension_ = Dimension::Fixed;
|
||||
bool use_alternative_screen_ = false;
|
||||
ScreenInteractive(int dimx,
|
||||
int dimy,
|
||||
Dimension dimension,
|
||||
bool use_alternative_screen);
|
||||
|
||||
bool track_mouse_ = true;
|
||||
|
||||
Sender<Task> task_sender_;
|
||||
Receiver<Task> task_receiver_;
|
||||
|
||||
std::string set_cursor_position;
|
||||
std::string reset_cursor_position;
|
||||
|
||||
std::atomic<bool> quit_ = false;
|
||||
std::thread event_listener_;
|
||||
std::thread animation_listener_;
|
||||
bool animation_requested_ = false;
|
||||
animation::TimePoint previous_animation_time_;
|
||||
|
||||
int cursor_x_ = 1;
|
||||
int cursor_y_ = 1;
|
||||
|
||||
bool mouse_captured = false;
|
||||
bool previous_frame_resized_ = false;
|
||||
|
||||
bool frame_valid_ = false;
|
||||
|
||||
friend class Loop;
|
||||
|
||||
public:
|
||||
class Private {
|
||||
public:
|
||||
static void Signal(ScreenInteractive& s, int signal) { s.Signal(signal); }
|
||||
};
|
||||
friend Private;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP */
|
||||
17
include/ftxui/component/task.hpp
Normal file
17
include/ftxui/component/task.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#ifndef FTXUI_COMPONENT_ANIMATION_HPP
|
||||
#define FTXUI_COMPONENT_ANIMATION_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <variant>
|
||||
#include "ftxui/component/event.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
class AnimationTask {};
|
||||
using Closure = std::function<void()>;
|
||||
using Task = std::variant<Event, Closure, AnimationTask>;
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_COMPONENT_ANIMATION_HPP
|
||||
Reference in New Issue
Block a user