文章目录
- component_base.hpp
-
- [ComponentBase 类](#ComponentBase 类)
- receiver.hpp
-
- [SenderImpl类 和 ReceiverImpl 类](#SenderImpl类 和 ReceiverImpl 类)
- mouse.hpp
-
- [Mouse 类](#Mouse 类)
- event.hpp
-
- [Event 类](#Event 类)
- screen_interactive.hpp
-
- [ScreenInteractive 类](#ScreenInteractive 类)
- loop.hpp
-
- [Loop 类](#Loop 类)
- animation.hpp
- component_options.hpp
-
- [EntryState 类](#EntryState 类)
- [UnderlineOption 类](#UnderlineOption 类)
- [AnimatedColorOption 类](#AnimatedColorOption 类)
- [MenuEntryOption 类](#MenuEntryOption 类)
- [MenuOption 类](#MenuOption 类)
- [ButtonOption 类](#ButtonOption 类)
- [CheckboxOption 类](#CheckboxOption 类)
- [InputState 类](#InputState 类)
- [InputOption 类](#InputOption 类)
- [RadioboxOption 类](#RadioboxOption 类)
- [ResizableSplitOption 类](#ResizableSplitOption 类)
- [SliderOption 类](#SliderOption 类)
- [WindowRenderState 类](#WindowRenderState 类)
- [WindowOptions 类](#WindowOptions 类)
- [DropdownOption 类](#DropdownOption 类)
- component.hpp
-
- [Container 组件容器](#Container 组件容器)
- [Button 按钮组件](#Button 按钮组件)
- [Checkbox 复选框组件](#Checkbox 复选框组件)
- [Input 输入框组件](#Input 输入框组件)
- [Menu 菜单组件](#Menu 菜单组件)
- [MenuEntry 菜单选择组件(垂直显示)](#MenuEntry 菜单选择组件(垂直显示))
- [Toggle 菜单选择组件(水平显示)](#Toggle 菜单选择组件(水平显示))
- [Radiobox 单选框组件](#Radiobox 单选框组件)
- [Dropdown 下拉框组件](#Dropdown 下拉框组件)
- [Slider 滑块组件](#Slider 滑块组件)
- [ResizableSplit 缩放和分割组件](#ResizableSplit 缩放和分割组件)
- [Renderer 渲染Element转为组件](#Renderer 渲染Element转为组件)
- [CatchEvent 事件捕获](#CatchEvent 事件捕获)
- [Maybe 可隐藏组件](#Maybe 可隐藏组件)
- [Modal 叠加组件](#Modal 叠加组件)
- [Collapsible 可折叠组件](#Collapsible 可折叠组件)
- [Hoverable 可包裹组件](#Hoverable 可包裹组件)
- [Window 可拖动窗口](#Window 可拖动窗口)
component_base.hpp
ComponentBase 类
定义组件基类。
class ComponentBase {
public:
// 必须显式构造。
explicit ComponentBase(Components children)
: children_(std::move(children)) {}
virtual ~ComponentBase();
ComponentBase() = default;
// 组件不可复制/移动。
ComponentBase(const ComponentBase&) = delete;
ComponentBase(ComponentBase&&) = delete;
ComponentBase& operator=(const ComponentBase&) = delete;
ComponentBase& operator=(ComponentBase&&) = delete;
// ------------- Component 层级关系 -----------------------
// 获取当前的父级Component组件
ComponentBase* Parent() const;
// 获取第 i 个子级Component组件
Component& ChildAt(size_t i);
// 获取子级Component组件的数量
size_t ChildCount() const;
// 返回当前组件在其父级Component中的索引。如果没有父级,则返回 -1。
int Index() const;
// 添加子级Component组件
void Add(Component children);
// 将当前组件从父级Component中分离
void Detach();
// 将所有子级Component分离
void DetachAllChildren();
// 渲染组件。
Element Render();
// 重写此函数,完成"Render"绘制功能
virtual Element OnRender();
// 处理事件。
// 默认情况下,减少具有懒惰 OR 的子级Component。
// 返回该事件是否已经被处理。
virtual bool OnEvent(Event);
// 处理动画步骤。
virtual void OnAnimation(animation::Params& params);
// ------------------- 焦点管理 ----------------------------------------------------------
// 如果此组件包含子组件,则这指示哪一个是活动的,如果没有活动,则为 nullptr。
//
// 如果根组件的 ActiveChild() 链包含该对象,我们就说该元素具有焦点。
virtual Component ActiveChild();
// 当组件包含可聚焦元素时返回 true。
// 使用键盘导航时,无法聚焦的组件将被跳过。
virtual bool Focusable() const;
// 判断当前组件是否在其父级的子组件列表中处于Active状态
bool Active() const;
// 判断所有祖先是否都处于Active状态。
bool Focused() const;
// 让 |child| 成为"Active"的一个。
virtual void SetActiveChild(ComponentBase* child);
// 设置指定的子级Component为Active状态。
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;
bool in_render = false;
};
receiver.hpp
定义了消息事件循环的基本功能,包含消息发送和接收接收的两个类。
SenderImpl类 和 ReceiverImpl 类
SenderImpl类实例用于实现发送消息功能。
ReceiverImpl类实例用于实现接收消息功能。
template <class T>
class SenderImpl {
public:
SenderImpl(const SenderImpl&) = delete;
SenderImpl(SenderImpl&&) = delete;
SenderImpl& operator=(const SenderImpl&) = delete;
SenderImpl& operator=(SenderImpl&&) = delete;
void Send(T t) { receiver_->Receive(std::move(t)); }
~SenderImpl() { receiver_->ReleaseSender(); }
Sender<T> Clone() { return receiver_->MakeSender(); }
private:
friend class ReceiverImpl<T>;
explicit 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() = default;
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_{0};
};
创建消息收发的组件实例。
template <class T>
Receiver<T> MakeReceiver() {
return std::make_unique<ReceiverImpl<T>>();
}
使用示例 :
初始化消息收发的组件实例
// 实例化 std::string 类型的消息组件。
auto receiver = MakeReceiver<std:string>();
// 通过接收对象创建两个发送对象,发送对象可以在其他线程执行消息发送操作。
auto sender_1= receiver->MakeSender();
auto sender_2 = receiver->MakeSender();
// (线程1)发送模块
sender_1->Send("hello");
// (线程2)发送模块
sender_2->Send("world");
// (线程3)接收模块
//只要存在Sender且存在消息队列有消息,则Receive函数返回 true。
std::string data;
while(receiver->Receive(&data)) {
printf("recv: %s\n", data.c_str());
}
mouse.hpp
定义鼠标类
Mouse 类
定义鼠标的基本信息。
// 定义鼠标按键类型
struct Mouse {
enum Button {
Left = 0,
Middle = 1,
Right = 2,
None = 3,
WheelUp = 4,
WheelDown = 5,
WheelLeft = 6, /// 仅支持终端。
WheelRight = 7, /// 仅支持终端。
};
// 定义鼠标按键动作
enum Motion {
Released = 0,
Pressed = 1,
Moved = 2,
};
// 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;
};
event.hpp
定义事件。
Event 类
定义事件的基本信息。
struct Event {
// -------- 构造函数部分 ----------------------------------------------
// 与给定键入字符串对应的事件。用户输入的字符。
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 CursorPosition(std::string, int x, int y); // Internal
// 与终端 DCS(设备控制字符串)对应的事件。终端发送的字符序列。终端焦点形状
static Event CursorShape(std::string, int shape); // Internal
// --- 键盘的方向按键 ---
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;
// --- 键盘的其他按键 ---
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 Insert;
static const Event Home;
static const Event End;
static const Event PageUp;
static const Event PageDown;
// --- 键盘的功能按键 ---
static const Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12;
// --- 键盘的控制+字母按键 ---
static const Event a, A, CtrlA, AltA, CtrlAltA;
static const Event b, B, CtrlB, AltB, CtrlAltB;
static const Event c, C, CtrlC, AltC, CtrlAltC;
static const Event d, D, CtrlD, AltD, CtrlAltD;
static const Event e, E, CtrlE, AltE, CtrlAltE;
static const Event f, F, CtrlF, AltF, CtrlAltF;
static const Event g, G, CtrlG, AltG, CtrlAltG;
static const Event h, H, CtrlH, AltH, CtrlAltH;
static const Event i, I, CtrlI, AltI, CtrlAltI;
static const Event j, J, CtrlJ, AltJ, CtrlAltJ;
static const Event k, K, CtrlK, AltK, CtrlAltK;
static const Event l, L, CtrlL, AltL, CtrlAltL;
static const Event m, M, CtrlM, AltM, CtrlAltM;
static const Event n, N, CtrlN, AltN, CtrlAltN;
static const Event o, O, CtrlO, AltO, CtrlAltO;
static const Event p, P, CtrlP, AltP, CtrlAltP;
static const Event q, Q, CtrlQ, AltQ, CtrlAltQ;
static const Event r, R, CtrlR, AltR, CtrlAltR;
static const Event s, S, CtrlS, AltS, CtrlAltS;
static const Event t, T, CtrlT, AltT, CtrlAltT;
static const Event u, U, CtrlU, AltU, CtrlAltU;
static const Event v, V, CtrlV, AltV, CtrlAltV;
static const Event w, W, CtrlW, AltW, CtrlAltW;
static const Event x, X, CtrlX, AltX, CtrlAltX;
static const Event y, Y, CtrlY, AltY, CtrlAltY;
static const Event z, Z, CtrlZ, AltZ, CtrlAltZ;
// --- 自定义按键 ---
static const Event Custom;
//--- 比较按键事件相关的函数 ---------------------------------------------------------
bool operator==(const Event& other) const { return input_ == other.input_; }
bool operator!=(const Event& other) const { return !operator==(other); }
bool operator<(const Event& other) const { return input_ < other.input_; }
// 获取事件的字符串内容
const std::string& input() const { return input_; }
// 判断事件是否为键盘按键触发类型
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_position() const { return type_ == Type::CursorPosition; }
// 获取事件的焦点坐标
int cursor_x() const { return data_.cursor.x; }
int cursor_y() const { return data_.cursor.y; }
// 判断事件是否存在焦点形状
bool is_cursor_shape() const { return type_ == Type::CursorShape; }
// 获取事件的焦点形状
int cursor_shape() const { return data_.cursor_shape; }
// 获取Debug字符串内容
std::string DebugString() const;
//--- 交互界面句柄 ----------------------------------------------------------
ScreenInteractive* screen_ = nullptr;
private:
friend ComponentBase;
friend ScreenInteractive;
enum class Type {
Unknown,
Character, // 键盘字符信息
Mouse, // 鼠标信息
CursorPosition, // 焦点位置
CursorShape, // 焦点形状
};
Type type_ = Type::Unknown; // 存储事件的类型
struct Cursor {
int x = 0;
int y = 0;
};//定义焦点坐标
union {
struct Mouse mouse;
struct Cursor cursor;
int cursor_shape;
} data_ = {}; // 存储事件的信息
std::string input_; // 存储事件对应字符串内容
};
screen_interactive.hpp
定义终端界面交互的基础功能
ScreenInteractive 类
该类继承了Screen类,提供了终端界面渲染和交互的基本功能。
class ScreenInteractive : public Screen {
public:
// 创建指定大小区域的终端界面交互
static ScreenInteractive FixedSize(int dimx, int dimy);
//创建一个占用完整Screen终端大小的终端界面交互。这将使用备用屏幕缓冲区来避免干扰终端内容。
static ScreenInteractive Fullscreen();
//创建一个占用完整Screen终端大小的终端界面交互。主屏幕缓冲区正在被占用。这意味着如果调整终端大小,先前的内容可能会与终端内容混淆。
static ScreenInteractive FullscreenPrimaryScreen();
//创建一个占用完整Screen终端大小的终端界面交互。这将使用备用屏幕缓冲区来避免干扰终端内容。
static ScreenInteractive FullscreenAlternateScreen();
//创建一个占用完整Component大小的终端界面交互。
static ScreenInteractive FitComponent();
//创建一个占用Screen终端宽度的终端界面交互(终端界面的高度取决于Component高度)。
static ScreenInteractive TerminalOutput();
// 可选. 必须在执行Loop()前调用。该函数作用用于控制是否进行跟踪鼠标控制。
void TrackMouse(bool enable = true);
// 返回当前活动屏幕,如果没有则返回 nullptr。
static ScreenInteractive* Active();
// 创建Loop循环,并启动主循环进行Component组件交互。
void Loop(Component);
// 停止主循环。
void Exit();
// 返回停止主循环的回调函数。
Closure ExitLoopClosure();
// 发布要由主循环执行的任务。
void Post(Task task);
// 发布要由主循环执行的事件(按键事件、鼠标事件)。
void PostEvent(Event event);
// 发布要由主循环执行的动画。
void RequestAnimationFrame();
// 尝试获取能够捕获鼠标的独特锁。如果鼠标尚未被捕获,则为唯一锁,否则为空。
CapturedMouse CaptureMouse();
// 装饰一个函数。输出的函数将以与输入函数类似的方式执行,但当前活动的屏幕终端钩子会被暂时卸载。
Closure WithRestoredIO(Closure);
// FTXUI 实现了 Ctrl-C 和 Ctrl-Z 的处理程序。
// 默认情况下,即使组件捕获了事件,这些处理程序也会执行。
// 这避免了用户处理每个事件时被应用程序捕获。但是在某些情况下,应用程序可能希望自行处理这些事件。
// 在这种情况下,应用程序可以通过调用以下函数并设置 force=true 来强制 FTXUI 不处理这些事件。
void ForceHandleCtrlC(bool force);
void ForceHandleCtrlZ(bool force);
// 选中功能
std::string GetSelection();
void SelectionChange(std::function<void()> callback);
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);
bool HandleSelection(bool handled, Event event);
void RefreshSelection();
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;
bool force_handle_ctrl_c_ = true;
bool force_handle_ctrl_z_ = true;
// The style of the cursor to restore on exit.
int cursor_reset_shape_ = 1;
// Selection API:
CapturedMouse selection_pending_;
struct SelectionData {
int start_x = -1;
int start_y = -1;
int end_x = -2;
int end_y = -2;
bool empty = true;
bool operator==(const SelectionData& other) const;
bool operator!=(const SelectionData& other) const;
};
SelectionData selection_data_;
SelectionData selection_data_previous_;
std::unique_ptr<Selection> selection_;
std::function<void()> selection_on_change_;
friend class Loop;
public:
class Private {
public:
static void Signal(ScreenInteractive& s, int signal) { s.Signal(signal); }
};
friend Private;
};
loop.hpp
Loop 类
定义Loop事件循环。
class Loop {
public:
Loop(ScreenInteractive* screen, Component component);
~Loop();
// 此类不可复制/移动。
Loop(const Loop&) = default;
Loop(Loop&&) = delete;
Loop& operator=(Loop&&) = delete;
Loop(const ScreenInteractive&) = delete;
Loop& operator=(const Loop&) = delete;
// 判断循环是否已经退出
bool HasQuitted();
// 执行循环。使"组件"处理每个待处理的任务/事件。如果前一帧无效,则可能会绘制新的一帧。
void RunOnce();
// 等待至少一个事件被处理并执行Loop::RunOnce()
void RunOnceBlocking();
// 执行循环,阻塞当前线程,直到循环退出。
void Run();
private:
ScreenInteractive* screen_;// 存储当前循环的终端交互界面
Component component_;//存储当前事件循环的组件。
};
animation.hpp
定义动画显示的功能以及算法。
// 获取当前激活的ScreenInteractive界面,执行动画显示。
void RequestAnimationFrame();
using Clock = std::chrono::steady_clock;
using TimePoint = std::chrono::time_point<Clock>;
using Duration = std::chrono::duration<float>;
// 定义时长参数
class Params {
public:
explicit 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:
explicit 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_;
};
component_options.hpp
定义component的options配置信息。
EntryState 类
定义组件的状态、激活、焦点状态配置信息。
struct EntryState {
std::string label; ///< 要显示的标签。
bool state; ///< 按钮/复选框/单选框的状态
bool active; ///< 该条目是否为活动条目。
bool focused; ///< 该条目是否是用户关注的条目。
int index; ///< 适用时条目的索引或 -1。
};
UnderlineOption 类
定义下划线的配置项
struct UnderlineOption {
bool enabled = false; // 是否使能下划线配置
Color color_active = Color::White; // Active状态下的颜色
Color color_inactive = Color::GrayDark; // 非Active状态下的颜色
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);
};
AnimatedColorOption 类
关于潜在动画颜色的选项。
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;
};
MenuEntryOption 类
MenuEntry 组件的选项。
struct MenuEntryOption {
ConstStringRef label = "MenuEntry";
std::function<Element(const EntryState& state)> transform;
AnimatedColorsOption animated_colors;
};
MenuOption 类
菜单组件的选项。
struct MenuOption {
// 标准构造函数:
static MenuOption Horizontal();
static MenuOption HorizontalAnimated();
static MenuOption Vertical();
static MenuOption VerticalAnimated();
static MenuOption Toggle();
ConstStringListRef entries; ///> 条目列表。
Ref<int> selected = 0; ///> 选定条目的索引。
// 样式风格:
UnderlineOption underline;
MenuEntryOption entries_option;
Direction direction = Direction::Down;
std::function<Element()> elements_prefix;
std::function<Element()> elements_infix;
std::function<Element()> elements_postfix;
// 监听器:
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;
};
ButtonOption 类
AnimatedButton 组件的选项。
struct ButtonOption {
// 标准构造函数
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 = [] {};
// 样式风格
std::function<Element(const EntryState&)> transform;
AnimatedColorsOption animated_colors;
};
CheckboxOption 类
复选框组件的选项。
struct CheckboxOption {
// 标准构造函数
static CheckboxOption Simple();
ConstStringRef label = "Checkbox";
Ref<bool> checked = false;
// 样式风格:
std::function<Element(const EntryState&)> transform;
// 监听器:
/// Called when the user change the state.
std::function<void()> on_change = [] {};
};
InputState 类
用于定义输入组件的样式。
struct InputState {
Element element;
bool hovered; ///< 输入是否被鼠标悬停。
bool focused; ///< 输入是否受到用户的关注。
bool is_placeholder; ///< 输入是否为空,显示占位符。
};
InputOption 类
输入组件的选项。
struct InputOption {
// 一组预定义的样式:
// 创建默认输入样式风格
static InputOption Default();
// 黑底白字样式,边距较高:
static InputOption Spacious();
/// 输入的内容。
StringRef content = "";
/// 当输入为空时的内容。
StringRef placeholder = "";
// 样式风格:
std::function<Element(InputState)> transform;
Ref<bool> password = false; ///< 使用'*'隐藏输入内容。
Ref<bool> multiline = true; ///< 输入是否可以是多行。
Ref<bool> insert = true; ///< 插入或改写字符模式。
/// 当内容改变时调用。
std::function<void()> on_change = [] {};
/// 当用户按下回车键时调用。
std::function<void()> on_enter = [] {};
// 光标的字符位置:
Ref<int> cursor_position = 0;
};
RadioboxOption 类
Radiobox 组件的选项。
struct RadioboxOption {
// 标准构造函数
static RadioboxOption Simple();
// 内容:
ConstStringListRef entries;
Ref<int> selected = 0;
// 样式风格:
std::function<Element(const EntryState&)> transform;
// 监听器:
/// 当选定的条目发生改变时调用。
std::function<void()> on_change = [] {};
Ref<int> focused_entry = 0;
};
ResizableSplitOption 类
定义可以缩放的配置。
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(); };
};
SliderOption 类
Slider
组件的选项。
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;
std::function<void()> on_change; ///> 当"值"更新时调用。
};
WindowRenderState 类
WindowOptions::render
使用的参数包。
struct WindowRenderState {
Element inner; ///< 该元素包裹在该窗口内。
const std::string& title; ///< 窗口的标题。
bool active = false; ///< 窗口是否为活动窗口。
bool drag = false; ///< 窗口是否正在被拖动。
bool resize = false; ///< 窗口是否正在调整大小。
bool hover_left = false; ///< 可调整大小的左侧是否处于悬停状态。
bool hover_right = false; ///< 可调整大小的右侧是否处于悬停状态。
bool hover_top = false; ///< 可调整大小的顶部是否处于悬停状态。
bool hover_down = false; ///< 可调整大小的下方是否处于悬停状态。
};
WindowOptions 类
"窗口"组件的选项。
struct WindowOptions {
Component inner; ///< 该窗口包裹的组件。
ConstStringRef title = ""; ///< 此窗口显示的标题。
Ref<int> left = 0; ///< 窗口左侧的位置。
Ref<int> top = 0; ///< 窗口顶部的位置。
Ref<int> width = 20; ///< 窗口的宽度。
Ref<int> height = 10; ///< 窗口的高度。
Ref<bool> resize_left = true; ///< 左侧可以调整大小吗?
Ref<bool> resize_right = true; ///< 右侧可以调整大小吗?
Ref<bool> resize_top = true; ///< 顶部可以调整大小吗?
Ref<bool> resize_down = true; ///< 下方可以调整大小吗?
/// 用于自定义窗口外观的可选函数:
std::function<Element(const WindowRenderState&)> render;
};
DropdownOption 类
下拉组件的选项。
struct DropdownOption {
/// 下拉菜单是否打开或关闭:
Ref<bool> open = false;
// 复选框的选项:
CheckboxOption checkbox;
// 单选框的选项:
RadioboxOption radiobox;
// 变换函数:
std::function<Element(bool open, Element checkbox, Element radiobox)>
transform;
};
component.hpp
该文件定义了常用的Component基本组件。
// 定义模版,用于创建特定的组件实例
template <class T, class... Args>
std::shared_ptr<T> Make(Args&&... args) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
// 管道运算符来装饰组件
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);
Container 组件容器
// 定义组件容器
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
Button 按钮组件
// 定义按钮组件
Component Button(ButtonOption options);
Component Button(ConstStringRef label,
std::function<void()> on_click,
ButtonOption options = ButtonOption::Simple());
使用示例:
ftxui::ButtonOption buttonOption = ftxui::ButtonOption::Animated( // 按钮的样式
ftxui::Color::Black, ftxui::Color::White,
ftxui::Color::Black, ftxui::Color::Yellow);
std::function<void()> on_click = [](){ // 点击按钮时被调用
spdlog::trace("on_click");
};
ftxui::Component button_layout = ftxui::Button("Button1", on_click, buttonOption);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(button_layout);

Checkbox 复选框组件
// 定义复选框组件
Component Checkbox(CheckboxOption options);
Component Checkbox(ConstStringRef label,
bool* checked,
CheckboxOption options = CheckboxOption::Simple());
使用示例:
bool is_checked = false;// 存储复选框状态
ftxui::CheckboxOption checkboxOption = ftxui::CheckboxOption::Simple();
checkboxOption.on_change = [&is_checked](){ // 复选框状态变化时被调用
spdlog::trace("on_change: {}", is_checked);
};
ftxui::Component checkbox_layout = ftxui::Checkbox("Item1", &is_checked, checkboxOption);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(checkbox_layout);

Input 输入框组件
// 定义输入框组件
Component Input(InputOption options = {});
Component Input(StringRef content, InputOption options = {});
Component Input(StringRef content,
StringRef placeholder,
InputOption options = {});
使用示例:
std::string input_data;//存储从输入框获取的内容
std::string placeholder = "please input data";// 输入框的提示内容
ftxui::InputOption inputOption = ftxui::InputOption::Spacious(); // 输入框配置选项
inputOption.password = false;// 非密码模式
inputOption.multiline = false;// 非多行模式
inputOption.insert = false; // 非插入模式
inputOption.on_change = [&input_data](){ // 输入内容变化时被调用
spdlog::trace("on_change: {}", input_data);
};
inputOption.on_enter = [&input_data](){ // 输入回车时被调用
spdlog::trace("on_enter: {}", input_data);
};
ftxui::Component input_layout = ftxui::Input(&input_data, "please input data", inputOption);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(input_layout);

Menu 菜单组件
// 定义菜单组件
Component Menu(MenuOption options);
Component Menu(ConstStringListRef entries,
int* selected_,
MenuOption options = MenuOption::Vertical());
使用示例:
std::vector<std::string> menu = { // 设置要显示的菜单列表
"menu_item1",
"menu_item2",
"menu_item3",
};
int selected_index = 0; // 存储选择的菜单选项索引
ftxui::MenuOption menuOption = ftxui::MenuOption::Vertical();//
menuOption.on_change = [&selected_index](){ // 选择项改变时被调用
spdlog::trace("on_change: {}", selected_index);
};
menuOption.on_enter = [&selected_index](){ // 输入回车按键时被调用
spdlog::trace("on_enter: {}", selected_index);
};
ftxui::Component menu_layout = ftxui::Menu(menu, &selected_index, menuOption);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(menu_layout);

MenuEntry 菜单选择组件(垂直显示)
// 定义菜单选项
Component MenuEntry(MenuEntryOption options);
Component MenuEntry(ConstStringRef label, MenuEntryOption options = {});
使用示例:
int selected = 0;
auto menu_layout = ftxui::Container::Vertical({
ftxui::MenuEntry("menu_entry 1"),
ftxui::MenuEntry("menu_entry 2"),
ftxui::MenuEntry("menu_entry 3"),
}, &selected);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(menu_layout);

Toggle 菜单选择组件(水平显示)
// 定义水平方向的菜单选项
Component Toggle(ConstStringListRef entries, int* selected);
使用示例:
std::vector<std::string> menu = { // 设置要显示的菜单列表
"menu_item1",
"menu_item2",
"menu_item3",
};
int selected_index = 0; // 存储选择的菜单选项索引
ftxui::Component toggle_layout = ftxui::Toggle(menu, &selected_index);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(toggle_layout);

Radiobox 单选框组件
// 定义单选框组件
Component Radiobox(RadioboxOption options);
Component Radiobox(ConstStringListRef entries,
int* selected_,
RadioboxOption options = {});
使用示例:
std::vector<std::string> radio_list = { // 设置要显示的单选列表
"radio_item1",
"radio_item2",
"radio_item3",
};
int selected_index = 0; // 存储选择的菜单选项索引
ftxui::RadioboxOption radioboxOption = ftxui::RadioboxOption::Simple();// 单选框配置项
radioboxOption.on_change = [&selected_index](){
spdlog::trace("on_change: {}", selected_index);
};
ftxui::Component radio_layout = ftxui::Radiobox(radio_list, &selected_index, radioboxOption);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(radio_layout);

Dropdown 下拉框组件
// 定义下拉框组件
Component Dropdown(ConstStringListRef entries, int* selected);
Component Dropdown(DropdownOption options);
使用示例:
std::vector<std::string> dropdown_list = { // 设置要显示的下拉菜单列表
"dropdown_item1",
"dropdown_item2",
"dropdown_item3",
};
int selected_index = 0; // 存储选择的菜单选项索引
ftxui::Component dropdown_layout = ftxui::Dropdown(dropdown_list, &selected_index);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(dropdown_layout);

Slider 滑块组件
// 定义通用Slider滑块组件
template <typename T>
Component Slider(SliderOption<T> options);
// 不使用 `SliderOption` 构造函数的简写
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);
使用示例:
int progress = 0;// 存储当前进度值
int slider_min = 0; // 配置进度最小值
int slider_max = 100; // 配置进度最大值
int slider_increment = 1; // 配置进度单步长度
ftxui::Component slider_layout = ftxui::Slider("slider_progress", &progress, slider_min, slider_max, slider_increment);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(slider_layout);

ResizableSplit 缩放和分割组件
// 定义可缩放的分割组件
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);
使用示例:
ftxui::ResizableSplitOption resizableSplitOption;
// 主Component
resizableSplitOption.main = ftxui::Renderer([]{ return ftxui::paragraph("this is long long long right text..."); });
// 副Component
resizableSplitOption.back = ftxui::Renderer([]{ return ftxui::paragraph("this is long long long left..."); });
// 设置偏移方向: 从上向下
resizableSplitOption.direction = ftxui::Direction::Up;
// 设置主Component的分割的大小: 2个单位
resizableSplitOption.main_size = 2;
// 设置自定义分割线样式: 虚线
resizableSplitOption.separator_func = []{ return ftxui::separatorStyled(ftxui::BorderStyle::DASHED); };
ftxui::Component resizableSplit_layout = ftxui::ResizableSplit(resizableSplitOption);
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(resizableSplit_layout);

Renderer 渲染Element转为组件
// 渲染Element元素,转为组件
Component Renderer(Component child, std::function<Element()>);
Component Renderer(std::function<Element()>);
Component Renderer(std::function<Element(bool /* focused */)>);
ComponentDecorator Renderer(ElementDecorator);
使用示例:
std::string text = "this is content..."; // 文本内容
// 将 Element 元素 转为 Component 组件。
ftxui::Component layout = ftxui::Renderer([&text](){
return ftxui::text(text);
});
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.Loop(layout);

CatchEvent 事件捕获
// 捕获组件的事件
Component CatchEvent(Component child, std::function<bool(Event)>);
ComponentDecorator CatchEvent(std::function<bool(Event)> on_event);
使用示例 :
std::string paragraph_text = "This is paragraph text...";
auto paragraph_view = ftxui::Renderer([¶graph_text](){
return ftxui::paragraph(paragraph_text) | ftxui::border;
});
auto screen = ftxui::ScreenInteractive::Fullscreen();
screen.ForceHandleCtrlC(false);// 设置false强制FTXUI不处理Ctrl+C信号
screen.ForceHandleCtrlZ(false);// 设置false强制FTXUI不处理Ctrl+Z信号
auto component = CatchEvent(paragraph_view, [&](ftxui::Event event) {
if (event == ftxui::Event::CtrlC) {
spdlog::trace("CtrlC");
screen.ExitLoopClosure()();
return true;// 返回true表示已经处理 Ctrl+C 事件,不让FTXUI触发ABORT退出信号
}
if (event == ftxui::Event::CtrlZ) {
spdlog::trace("CtrlZ");
screen.ExitLoopClosure()();
return true;// 返回true表示已经处理 Ctrl+Z 事件,不让FTXUI触发ABORT退出信号
}
return false;
});
screen.Loop(component);

Maybe 可隐藏组件
// 隐藏一个组件。仅当 show=true 时才显示被隐藏的组件
Component Maybe(Component, const bool* show);
Component Maybe(Component, std::function<bool()>);
ComponentDecorator Maybe(const bool* show);
ComponentDecorator Maybe(std::function<bool()>);
使用示例:
bool show_status = true; // 控制paragraph_layout显示/隐藏
auto button_show = ftxui::Button("Show", [&show_status](){
show_status = true;
}, ftxui::ButtonOption::Border());
auto button_hidden = ftxui::Button("Hidden", [&show_status](){
show_status = false;
}, ftxui::ButtonOption::Border());
auto button_layout = ftxui::Container::Horizontal({
button_show,
button_hidden,
});
std::string paragraph_text = "This is paragraph text...";
auto paragraph_layout = ftxui::Renderer([¶graph_text](){
return ftxui::paragraph(paragraph_text) | ftxui::border;
});
auto layout = ftxui::Container::Vertical({
button_layout,
ftxui::Maybe(paragraph_layout, &show_status),// 根据show_status变量状态控制是否隐藏paragraph_layout
});
auto screen = ftxui::ScreenInteractive::Fullscreen();
screen.ForceHandleCtrlC(false);
screen.ForceHandleCtrlZ(false);
auto component = CatchEvent(layout, [&](ftxui::Event event) {
if (event == ftxui::Event::CtrlC) {
spdlog::trace("CtrlC");
screen.ExitLoopClosure()();
return true;
}
if (event == ftxui::Event::CtrlZ) {
spdlog::trace("CtrlZ");
screen.ExitLoopClosure()();
return true;
}
return false;
});
screen.Loop(component);
Modal 叠加组件
// 叠加一个组件。在main组件的外层叠加显示一个modal组件,仅当 show_modal=true 时才会叠加显示。
Component Modal(Component main, Component modal, const bool* show_modal);
ComponentDecorator Modal(Component modal, const bool* show_modal);
使用示例:
bool show_status = true; // 控制是否叠加model_layout
auto button_show = ftxui::Button("Show", [&show_status](){
show_status = true;
}, ftxui::ButtonOption::Border());
auto button_hidden = ftxui::Button("Hidden", [&show_status](){
show_status = false;
}, ftxui::ButtonOption::Border());
auto button_layout = ftxui::Container::Horizontal({
button_show,
button_hidden,
});
std::string paragraph_text = "This is paragraph text...";
auto paragraph_layout = ftxui::Renderer([¶graph_text](){
return ftxui::paragraph(paragraph_text) | ftxui::border;
});
std::string model_text = "This is model_text text...";
auto model_layout = ftxui::Renderer([&model_text](){
return ftxui::paragraph(model_text) | ftxui::border;
});
auto layout = ftxui::Container::Vertical({
button_layout,
ftxui::Modal(paragraph_layout, model_layout, &show_status),// 根据show_status变量状态控制是否将model_layout叠加到paragraph_layout外层
});
auto screen = ftxui::ScreenInteractive::Fullscreen();
screen.ForceHandleCtrlC(false);
screen.ForceHandleCtrlZ(false);
auto component = CatchEvent(layout, [&](ftxui::Event event) {
if (event == ftxui::Event::CtrlC) {
spdlog::trace("CtrlC");
screen.ExitLoopClosure()();
return true;
}
if (event == ftxui::Event::CtrlZ) {
spdlog::trace("CtrlZ");
screen.ExitLoopClosure()();
return true;
}
return false;
});
screen.Loop(component);
Collapsible 可折叠组件
// 可折叠组件。它显示一个带箭头的复选框。一旦激活,子项就会显示出来。
Component Collapsible(ConstStringRef label,
Component child,
Ref<bool> show = false);
使用示例:
bool show_status = true; // 控制paragraph_layout显示/折叠
auto button_show = ftxui::Button("Show", [&show_status](){
show_status = true;
}, ftxui::ButtonOption::Border());
auto button_hidden = ftxui::Button("Hidden", [&show_status](){
show_status = false;
}, ftxui::ButtonOption::Border());
auto button_layout = ftxui::Container::Horizontal({
button_show,
button_hidden,
});
std::string paragraph_text = "This is paragraph text...";
auto paragraph_layout = ftxui::Renderer([¶graph_text](){
return ftxui::paragraph(paragraph_text) | ftxui::border;
});
auto layout = ftxui::Container::Vertical({
button_layout,
ftxui::Collapsible("paragraph", paragraph_layout, &show_status),// 根据show_status变量状态控制是否折叠paragraph_layout
});
auto screen = ftxui::ScreenInteractive::Fullscreen();
screen.ForceHandleCtrlC(false);
screen.ForceHandleCtrlZ(false);
auto component = CatchEvent(layout, [&](ftxui::Event event) {
if (event == ftxui::Event::CtrlC) {
spdlog::trace("CtrlC");
screen.ExitLoopClosure()();
return true;
}
if (event == ftxui::Event::CtrlZ) {
spdlog::trace("CtrlZ");
screen.ExitLoopClosure()();
return true;
}
return false;
});
screen.Loop(component);
Hoverable 可包裹组件
// 包裹一个组件。使其能够知道鼠标是否悬停在组件上。
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);
使用示例:
Window 可拖动窗口
// 可拖动/可调整大小的窗口。
// 要使用多个窗口,必须使用 `Container::Stacked({...})` 组件将它们堆叠起来;
Component Window(WindowOptions option);