FTXUI 笔记(五)——基本交互组件

文章目录

  • 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;
};

MenuEntry 组件的选项。

复制代码
struct MenuEntryOption {
  ConstStringRef label = "MenuEntry";
  std::function<Element(const EntryState& state)> transform;
  AnimatedColorsOption animated_colors;
};

菜单组件的选项。

复制代码
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;
};

下拉组件的选项。

复制代码
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);
复制代码
// 定义菜单组件
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);
复制代码
// 定义菜单选项
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);
复制代码
// 定义下拉框组件
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([&paragraph_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([&paragraph_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);


复制代码
// 叠加一个组件。在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([&paragraph_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([&paragraph_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);
相关推荐
码农新猿类2 小时前
服务器本地搭建
linux·网络·c++
GOTXX2 小时前
【Qt】Qt Creator开发基础:项目创建、界面解析与核心概念入门
开发语言·数据库·c++·qt·图形渲染·图形化界面·qt新手入门
徐行1103 小时前
C++核心机制-this 指针传递与内存布局分析
开发语言·c++
序属秋秋秋3 小时前
算法基础_数据结构【单链表 + 双链表 + 栈 + 队列 + 单调栈 + 单调队列】
c语言·数据结构·c++·算法
mldl_4 小时前
(个人题解)第十六届蓝桥杯大赛软件赛省赛C/C++ 研究生组
c语言·c++·蓝桥杯
一个小白14 小时前
C++ 用红黑树封装map/set
java·数据库·c++
Lenyiin4 小时前
《 C++ 点滴漫谈: 三十三 》当函数成为参数:解密 C++ 回调函数的全部姿势
c++·回调函数·lenyiin
埜玊5 小时前
C++之 多继承
c++
1024熙6 小时前
【C++】——lambda表达式
开发语言·数据结构·c++·算法·lambda表达式
mahuifa7 小时前
(2)VTK C++开发示例 --- 绘制多面锥体
c++·vtk·cmake·3d开发