mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 18:48:11 +08:00 
			
		
		
		
	Animation (#355)
This commit is contained in:
		
							
								
								
									
										119
									
								
								include/ftxui/component/animation.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								include/ftxui/component/animation.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| #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<double>; | ||||
|  | ||||
| // 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 */ | ||||
|  | ||||
| // 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. | ||||
| @@ -8,7 +8,7 @@ | ||||
| #include <vector>      // for vector | ||||
|  | ||||
| #include "ftxui/component/component_base.hpp"     // for Component, Components | ||||
| #include "ftxui/component/component_options.hpp"  // for ButtonOption, CheckboxOption, InputOption, MenuOption, RadioboxOption, ToggleOption | ||||
| #include "ftxui/component/component_options.hpp"  // for ButtonOption, CheckboxOption (ptr only), InputOption (ptr only), MenuEntryOption (ptr only), MenuOption, RadioboxOption (ptr only) | ||||
| #include "ftxui/dom/elements.hpp"                 // for Element | ||||
| #include "ftxui/util/ref.hpp"  // for Ref, ConstStringRef, ConstStringListRef, StringRef | ||||
|  | ||||
| @@ -19,7 +19,6 @@ struct Event; | ||||
| struct InputOption; | ||||
| struct MenuOption; | ||||
| struct RadioboxOption; | ||||
| struct ToggleOption; | ||||
| struct MenuEntryOption; | ||||
|  | ||||
| template <class T, class... Args> | ||||
| @@ -46,11 +45,11 @@ Component Tab(Components children, int* selector); | ||||
|  | ||||
| Component Button(ConstStringRef label, | ||||
|                  std::function<void()> on_click, | ||||
|                  Ref<ButtonOption> = {}); | ||||
|                  Ref<ButtonOption> = ButtonOption::Simple()); | ||||
|  | ||||
| Component Checkbox(ConstStringRef label, | ||||
|                    bool* checked, | ||||
|                    Ref<CheckboxOption> option = {}); | ||||
|                    Ref<CheckboxOption> option = CheckboxOption::Simple()); | ||||
|  | ||||
| Component Input(StringRef content, | ||||
|                 ConstStringRef placeholder, | ||||
| @@ -58,8 +57,7 @@ Component Input(StringRef content, | ||||
|  | ||||
| Component Menu(ConstStringListRef entries, | ||||
|                int* selected_, | ||||
|                Ref<MenuOption> = {}); | ||||
|  | ||||
|                Ref<MenuOption> = MenuOption::Vertical()); | ||||
| Component MenuEntry(ConstStringRef label, Ref<MenuEntryOption> = {}); | ||||
|  | ||||
| Component Dropdown(ConstStringListRef entries, int* selected); | ||||
| @@ -67,10 +65,7 @@ Component Dropdown(ConstStringListRef entries, int* selected); | ||||
| Component Radiobox(ConstStringListRef entries, | ||||
|                    int* selected_, | ||||
|                    Ref<RadioboxOption> option = {}); | ||||
|  | ||||
| Component Toggle(ConstStringListRef entries, | ||||
|                  int* selected, | ||||
|                  Ref<ToggleOption> option = {}); | ||||
| Component Toggle(ConstStringListRef entries, int* selected); | ||||
|  | ||||
| template <class T>  // T = {int, float, long} | ||||
| Component Slider(ConstStringRef label, T* value, T min, T max, T increment); | ||||
|   | ||||
| @@ -13,6 +13,10 @@ 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>; | ||||
| @@ -42,6 +46,9 @@ class ComponentBase { | ||||
|   // 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, | ||||
|   | ||||
| @@ -1,58 +1,136 @@ | ||||
| #ifndef FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP | ||||
| #define FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP | ||||
|  | ||||
| #include <ftxui/dom/elements.hpp> | ||||
| #include <ftxui/util/ref.hpp> | ||||
| #include <chrono>                         // for milliseconds | ||||
| #include <ftxui/component/animation.hpp>  // for Duration, QuadraticInOut, Function | ||||
| #include <ftxui/dom/elements.hpp>  // for Decorator, bold, inverted, operator|, Element, nothing | ||||
| #include <ftxui/util/ref.hpp>  // for Ref | ||||
| #include <functional>          // for function | ||||
| #include <optional>            // for optional | ||||
| #include <string>              // for string, allocator | ||||
|  | ||||
| #include "ftxui/screen/color.hpp"  // for Color, Color::GrayDark, Color::White | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| /// @brief Option for the Menu component. | ||||
| /// @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 MenuOption { | ||||
|   Decorator style_normal = nothing;    ///< style. | ||||
|   Decorator style_focused = inverted;  ///< Style when focused. | ||||
|   Decorator style_selected = bold;     ///< Style when selected. | ||||
|   Decorator style_selected_focused = | ||||
|       Decorator(inverted) | bold;  ///< Style when selected and focused. | ||||
| struct AnimatedColorOption { | ||||
|   void Set( | ||||
|       Color inactive, | ||||
|       Color active, | ||||
|       animation::Duration duration = std::chrono::milliseconds(250), | ||||
|       animation::easing::Function function = animation::easing::QuadraticInOut); | ||||
|  | ||||
|   /// Called when the selected entry changes. | ||||
|   std::function<void()> on_change = [] {}; | ||||
|   /// Called when the user presses enter. | ||||
|   std::function<void()> on_enter = [] {}; | ||||
|   bool enabled = false; | ||||
|   Color inactive; | ||||
|   Color active; | ||||
|   animation::Duration duration = std::chrono::milliseconds(250); | ||||
|   animation::easing::Function function = animation::easing::QuadraticInOut; | ||||
| }; | ||||
|  | ||||
|   Ref<int> focused_entry = 0; | ||||
| struct AnimatedColorsOption { | ||||
|   AnimatedColorOption background; | ||||
|   AnimatedColorOption foreground; | ||||
| }; | ||||
|  | ||||
| /// @brief Option for the MenuEntry component. | ||||
| /// @ingroup component | ||||
| struct MenuEntryOption { | ||||
|   Decorator style_normal = nothing;    ///< style. | ||||
|   Decorator style_focused = inverted;  ///< Style when focused. | ||||
|   Decorator style_selected = bold;     ///< Style when selected. | ||||
|   Decorator style_selected_focused = | ||||
|       Decorator(inverted) | bold;  ///< Style when selected and focused. | ||||
|   std::function<Element(EntryState state)> transform; | ||||
|   AnimatedColorsOption animated_colors; | ||||
| }; | ||||
|  | ||||
| /// @brief Option for the Button component. | ||||
| /// @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(); | ||||
|  | ||||
|   // Style: | ||||
|   UnderlineOption underline; | ||||
|   MenuEntryOption entries; | ||||
|   enum Direction { Up, Down, Left, Right }; | ||||
|   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 seelcted 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 { | ||||
|   /// Whether to show a border around the button. | ||||
|   bool border = true; | ||||
|   // 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); | ||||
|  | ||||
|   // Style: | ||||
|   std::function<Element(EntryState)> transform; | ||||
|   AnimatedColorsOption animated_colors; | ||||
| }; | ||||
|  | ||||
| /// @brief Option for the Checkbox component. | ||||
| /// @ingroup component | ||||
| struct CheckboxOption { | ||||
|   std::string style_checked = "▣ ";    ///< Prefix for a "checked" state. | ||||
|   std::string style_unchecked = "☐ ";  ///< Prefix for a "unchecked" state. | ||||
|   Decorator style_normal = nothing;    ///< style. | ||||
|   Decorator style_focused = inverted;  ///< Style when focused. | ||||
|   Decorator style_selected = bold;     ///< Style when selected. | ||||
|   Decorator style_selected_focused = | ||||
|       Decorator(inverted) | bold;  ///< Style when selected and focused. | ||||
|   // Standard constructors: | ||||
|   static CheckboxOption Simple(); | ||||
|  | ||||
|   // Style: | ||||
|   std::function<Element(EntryState)> transform; | ||||
|  | ||||
|   // Observer: | ||||
|   /// Called when the user change the state. | ||||
|   std::function<void()> on_change = []() {}; | ||||
|   std::function<void()> on_change = [] {}; | ||||
| }; | ||||
|  | ||||
| /// @brief Option for the Input component. | ||||
| @@ -74,34 +152,15 @@ struct InputOption { | ||||
| /// @brief Option for the Radiobox component. | ||||
| /// @ingroup component | ||||
| struct RadioboxOption { | ||||
|   std::string style_checked = "◉ ";    ///< Prefix for a "checked" state. | ||||
|   std::string style_unchecked = "○ ";  ///< Prefix for a "unchecked" state. | ||||
|   Decorator style_normal = nothing;    ///< style. | ||||
|   Decorator style_focused = inverted;  ///< Style when focused. | ||||
|   Decorator style_selected = bold;     ///< Style when selected. | ||||
|   Decorator style_selected_focused = | ||||
|       Decorator(inverted) | bold;  ///< Style when selected and focused. | ||||
|   // Standard constructors: | ||||
|   static RadioboxOption Simple(); | ||||
|  | ||||
|   /// Called when the selected entry changes. | ||||
|   std::function<void()> on_change = []() {}; | ||||
|  | ||||
|   Ref<int> focused_entry = 0; | ||||
| }; | ||||
|  | ||||
| /// @brief Option for the Toggle component. | ||||
| /// @ingroup component | ||||
| struct ToggleOption { | ||||
|   Decorator style_normal = nothing;    ///< style. | ||||
|   Decorator style_focused = inverted;  ///< Style when focused. | ||||
|   Decorator style_selected = bold;     ///< Style when selected. | ||||
|   Decorator style_selected_focused = | ||||
|       Decorator(inverted) | bold;  ///< Style when selected and focused. | ||||
|   // Style: | ||||
|   std::function<Element(EntryState)> transform; | ||||
|  | ||||
|   // Observers: | ||||
|   /// Called when the selected entry changes. | ||||
|   std::function<void()> on_change = [] {}; | ||||
|   /// Called when the user presses enter. | ||||
|   std::function<void()> on_enter = [] {}; | ||||
|  | ||||
|   Ref<int> focused_entry = 0; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #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 Closure, Task | ||||
| @@ -23,16 +24,21 @@ class ScreenInteractivePrivate; | ||||
|  | ||||
| class ScreenInteractive : public Screen { | ||||
|  public: | ||||
|   // Constructors: | ||||
|   static ScreenInteractive FixedSize(int dimx, int dimy); | ||||
|   static ScreenInteractive Fullscreen(); | ||||
|   static ScreenInteractive FitComponent(); | ||||
|   static ScreenInteractive TerminalOutput(); | ||||
|  | ||||
|   // Return the currently active screen, nullptr if none. | ||||
|   static ScreenInteractive* Active(); | ||||
|  | ||||
|   void Loop(Component); | ||||
|   Closure ExitLoopClosure(); | ||||
|  | ||||
|   void Post(Task task); | ||||
|   void PostEvent(Event event); | ||||
|   void RequestAnimationFrame(); | ||||
|  | ||||
|   CapturedMouse CaptureMouse(); | ||||
|  | ||||
| @@ -72,6 +78,9 @@ class ScreenInteractive : public Screen { | ||||
|  | ||||
|   std::atomic<bool> quit_ = false; | ||||
|   std::thread event_listener_; | ||||
|   std::thread animation_listener_; | ||||
|   bool animation_requested_ = true; | ||||
|   animation::TimePoint previous_animation_time; | ||||
|  | ||||
|   int cursor_x_ = 1; | ||||
|   int cursor_y_ = 1; | ||||
|   | ||||
| @@ -1,12 +1,18 @@ | ||||
| #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>; | ||||
| using Task = std::variant<Event, Closure, AnimationTask>; | ||||
| }  // namespace ftxui | ||||
|  | ||||
| #endif  // FTXUI_COMPONENT_ANIMATION_HPP | ||||
|  | ||||
| // 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. | ||||
|   | ||||
| @@ -43,6 +43,14 @@ Element separatorEmpty(); | ||||
| Element separatorStyled(BorderStyle); | ||||
| Element separator(Pixel); | ||||
| Element separatorCharacter(std::string); | ||||
| Element separatorHSelector(float left, | ||||
|                            float right, | ||||
|                            Color background, | ||||
|                            Color foreground); | ||||
| Element separatorVSelector(float up, | ||||
|                            float down, | ||||
|                            Color background, | ||||
|                            Color foreground); | ||||
| Element gauge(float ratio); | ||||
| Element gaugeLeft(float ratio); | ||||
| Element gaugeRight(float ratio); | ||||
|   | ||||
| @@ -27,6 +27,7 @@ class Color { | ||||
|   Color(uint8_t red, uint8_t green, uint8_t blue); | ||||
|   static Color RGB(uint8_t red, uint8_t green, uint8_t blue); | ||||
|   static Color HSV(uint8_t hue, uint8_t saturation, uint8_t value); | ||||
|   static Color Interpolate(float t, const Color& a, const Color& b); | ||||
|  | ||||
|   //--------------------------- | ||||
|   // List of colors: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Arthur Sonzogni
					Arthur Sonzogni