commit a8e1193e120a561394cd02190ad6fddbce6fa64f Author: François Date: Fri Mar 21 18:47:49 2025 +0100 Initial commit diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f25feec --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. + // Pointez pour afficher la description des attributs existants. + // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Lancer", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/essim", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": true, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Activer l'impression en mode Pretty pour gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Définir la version désassemblage sur Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ], + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bceb476 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.12) + +project(essim + LANGUAGES CXX + VERSION 0.1 + DESCRIPTION "System digital twin." +) + +set(DIR_LIBS ${CMAKE_SOURCE_DIR}/libs) +file(GLOB_RECURSE ALL_SOURCES "src/*.cpp") + +file(GLOB_RECURSE LIB_FTXUI "lib/ftxui/*.a") + + +add_executable( + essim + ${ALL_SOURCES} +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +target_link_libraries( + essim PRIVATE ${LIB_FTXUI} +) \ No newline at end of file diff --git a/include/ftxui/component/animation.hpp b/include/ftxui/component/animation.hpp new file mode 100644 index 0000000..c9f665e --- /dev/null +++ b/include/ftxui/component/animation.hpp @@ -0,0 +1,118 @@ +// Copyright 2022 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_ANIMATION_HPP +#define FTXUI_ANIMATION_HPP + +#include // for milliseconds, duration, steady_clock, time_point +#include // 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; +using Duration = std::chrono::duration; + +// 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; +// 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 */ diff --git a/include/ftxui/component/captured_mouse.hpp b/include/ftxui/component/captured_mouse.hpp new file mode 100644 index 0000000..4ed6d75 --- /dev/null +++ b/include/ftxui/component/captured_mouse.hpp @@ -0,0 +1,17 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_CAPTURED_MOUSE_HPP +#define FTXUI_CAPTURED_MOUSE_HPP + +#include + +namespace ftxui { +class CapturedMouseInterface { + public: + virtual ~CapturedMouseInterface() = default; +}; +using CapturedMouse = std::unique_ptr; +} // namespace ftxui + +#endif /* end of include guard: FTXUI_CAPTURED_MOUSE_HPP */ diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp new file mode 100644 index 0000000..9847603 --- /dev/null +++ b/include/ftxui/component/component.hpp @@ -0,0 +1,142 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_HPP +#define FTXUI_COMPONENT_HPP + +#include // for function +#include // for make_shared, shared_ptr +#include // for wstring +#include // for forward +#include // for vector + +#include "ftxui/component/component_base.hpp" // for Component, Components +#include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, MenuOption +#include "ftxui/dom/elements.hpp" // for Element +#include "ftxui/util/ref.hpp" // for ConstRef, Ref, ConstStringRef, ConstStringListRef, StringRef + +namespace ftxui { +struct ButtonOption; +struct CheckboxOption; +struct Event; +struct InputOption; +struct MenuOption; +struct RadioboxOption; +struct MenuEntryOption; + +template +std::shared_ptr Make(Args&&... args) { + return std::make_shared(std::forward(args)...); +} + +// Pipe operator to decorate components. +using ComponentDecorator = std::function; +using ElementDecorator = std::function; +Component operator|(Component component, ComponentDecorator decorator); +Component operator|(Component component, ElementDecorator decorator); +Component& operator|=(Component& component, ComponentDecorator decorator); +Component& operator|=(Component& component, ElementDecorator decorator); + +namespace Container { +Component Vertical(Components children); +Component Vertical(Components children, int* selector); +Component Horizontal(Components children); +Component Horizontal(Components children, int* selector); +Component Tab(Components children, int* selector); +Component Stacked(Components children); +} // namespace Container + +Component Button(ButtonOption options); +Component Button(ConstStringRef label, + std::function on_click, + ButtonOption options = ButtonOption::Simple()); + +Component Checkbox(CheckboxOption options); +Component Checkbox(ConstStringRef label, + bool* checked, + CheckboxOption options = CheckboxOption::Simple()); + +Component Input(InputOption options = {}); +Component Input(StringRef content, InputOption options = {}); +Component Input(StringRef content, + StringRef placeholder, + InputOption options = {}); + +Component Menu(MenuOption options); +Component Menu(ConstStringListRef entries, + int* selected_, + MenuOption options = MenuOption::Vertical()); +Component MenuEntry(MenuEntryOption options); +Component MenuEntry(ConstStringRef label, MenuEntryOption options = {}); + +Component Radiobox(RadioboxOption options); +Component Radiobox(ConstStringListRef entries, + int* selected_, + RadioboxOption options = {}); + +Component Dropdown(ConstStringListRef entries, int* selected); +Component Toggle(ConstStringListRef entries, int* selected); + +// General slider constructor: +template +Component Slider(SliderOption options); + +// Shorthand without the `SliderOption` constructor: +Component Slider(ConstStringRef label, + Ref value, + ConstRef min = 0, + ConstRef max = 100, + ConstRef increment = 5); +Component Slider(ConstStringRef label, + Ref value, + ConstRef min = 0.f, + ConstRef max = 100.f, + ConstRef increment = 5.f); +Component Slider(ConstStringRef label, + Ref value, + ConstRef min = 0l, + ConstRef max = 100l, + ConstRef increment = 5l); + +Component ResizableSplit(ResizableSplitOption options); +Component ResizableSplitLeft(Component main, Component back, int* main_size); +Component ResizableSplitRight(Component main, Component back, int* main_size); +Component ResizableSplitTop(Component main, Component back, int* main_size); +Component ResizableSplitBottom(Component main, Component back, int* main_size); + +Component Renderer(Component child, std::function); +Component Renderer(std::function); +Component Renderer(std::function); +ComponentDecorator Renderer(ElementDecorator); + +Component CatchEvent(Component child, std::function); +ComponentDecorator CatchEvent(std::function on_event); + +Component Maybe(Component, const bool* show); +Component Maybe(Component, std::function); +ComponentDecorator Maybe(const bool* show); +ComponentDecorator Maybe(std::function); + +Component Modal(Component main, Component modal, const bool* show_modal); +ComponentDecorator Modal(Component modal, const bool* show_modal); + +Component Collapsible(ConstStringRef label, + Component child, + Ref show = false); + +Component Hoverable(Component component, bool* hover); +Component Hoverable(Component component, + std::function on_enter, + std::function on_leave); +Component Hoverable(Component component, // + std::function on_change); +ComponentDecorator Hoverable(bool* hover); +ComponentDecorator Hoverable(std::function on_enter, + std::function on_leave); +ComponentDecorator Hoverable(std::function on_change); + +Component Window(WindowOptions option); + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_HPP */ diff --git a/include/ftxui/component/component_base.hpp b/include/ftxui/component/component_base.hpp new file mode 100644 index 0000000..1e3fa13 --- /dev/null +++ b/include/ftxui/component/component_base.hpp @@ -0,0 +1,98 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_BASE_HPP +#define FTXUI_COMPONENT_BASE_HPP + +#include // for unique_ptr +#include // for vector + +#include "ftxui/component/captured_mouse.hpp" // for CaptureMouse +#include "ftxui/dom/elements.hpp" // for Element + +namespace ftxui { + +class Delegate; +class Focus; +struct Event; + +namespace animation { +class Params; +} // namespace animation + +class ComponentBase; +using Component = std::shared_ptr; +using Components = std::vector; + +/// @brief It implement rendering itself as ftxui::Element. It implement +/// keyboard navigation by responding to ftxui::Event. +/// @ingroup component +class ComponentBase { + public: + // virtual Destructor. + virtual ~ComponentBase(); + + ComponentBase() = default; + + // A component is not copiable. + ComponentBase(const ComponentBase&) = delete; + void operator=(const ComponentBase&) = delete; + + // Component hierarchy: + ComponentBase* Parent() const; + Component& ChildAt(size_t i); + size_t ChildCount() const; + void Add(Component children); + void Detach(); + void DetachAllChildren(); + + // Renders the component. + virtual Element Render(); + + // Handles an event. + // By default, reduce on children with a lazy OR. + // + // Returns whether the event was handled or not. + virtual bool OnEvent(Event); + + // Handle an animation step. + virtual void OnAnimation(animation::Params& params); + + // Focus management ---------------------------------------------------------- + // + // If this component contains children, this indicates which one is active, + // nullptr if none is active. + // + // We say an element has the focus if the chain of ActiveChild() from the + // root component contains this object. + virtual Component ActiveChild(); + + // Return true when the component contains focusable elements. + // The non focusable Component will be skipped when navigating using the + // keyboard. + virtual bool Focusable() const; + + // Whether this is the active child of its parent. + bool Active() const; + // Whether all the ancestors are active. + bool Focused() const; + + // Make the |child| to be the "active" one. + virtual void SetActiveChild(ComponentBase* child); + void SetActiveChild(Component child); + + // Configure all the ancestors to give focus to this component. + void TakeFocus(); + + protected: + CapturedMouse CaptureMouse(const Event& event); + + Components children_; + + private: + ComponentBase* parent_ = nullptr; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_BASE_HPP */ diff --git a/include/ftxui/component/component_options.hpp b/include/ftxui/component/component_options.hpp new file mode 100644 index 0000000..b401b6d --- /dev/null +++ b/include/ftxui/component/component_options.hpp @@ -0,0 +1,267 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP +#define FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP + +#include // for milliseconds +#include // for Duration, QuadraticInOut, Function +#include // for Direction, Direction::Left, Direction::Right, Direction::Down +#include // for Element, separator +#include // for Ref, ConstRef, StringRef +#include // for function +#include // for optional +#include // for string + +#include "ftxui/component/component_base.hpp" // for Component +#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White + +namespace ftxui { + +/// @brief arguments for |ButtonOption::transform|, |CheckboxOption::transform|, +/// |Radiobox::transform|, |MenuEntryOption::transform|, +/// |MenuOption::transform|. +struct EntryState { + std::string label; /// < The label to display. + bool state; /// < The state of the button/checkbox/radiobox + bool active; /// < Whether the entry is the active one. + bool focused; /// < Whether the entry is one focused by the user. +}; + +struct UnderlineOption { + bool enabled = false; + + Color color_active = Color::White; + Color color_inactive = Color::GrayDark; + + animation::easing::Function leader_function = + animation::easing::QuadraticInOut; + animation::easing::Function follower_function = + animation::easing::QuadraticInOut; + + animation::Duration leader_duration = std::chrono::milliseconds(250); + animation::Duration leader_delay = std::chrono::milliseconds(0); + animation::Duration follower_duration = std::chrono::milliseconds(250); + animation::Duration follower_delay = std::chrono::milliseconds(0); + + void SetAnimation(animation::Duration d, animation::easing::Function f); + void SetAnimationDuration(animation::Duration d); + void SetAnimationFunction(animation::easing::Function f); + void SetAnimationFunction(animation::easing::Function f_leader, + animation::easing::Function f_follower); +}; + +/// @brief Option about a potentially animated color. +/// @ingroup component +struct AnimatedColorOption { + void Set( + Color inactive, + Color active, + animation::Duration duration = std::chrono::milliseconds(250), + animation::easing::Function function = animation::easing::QuadraticInOut); + + bool enabled = false; + Color inactive; + Color active; + animation::Duration duration = std::chrono::milliseconds(250); + animation::easing::Function function = animation::easing::QuadraticInOut; +}; + +struct AnimatedColorsOption { + AnimatedColorOption background; + AnimatedColorOption foreground; +}; + +/// @brief Option for the MenuEntry component. +/// @ingroup component +struct MenuEntryOption { + ConstStringRef label = "MenuEntry"; + std::function transform; + AnimatedColorsOption animated_colors; +}; + +/// @brief Option for the Menu component. +/// @ingroup component +struct MenuOption { + // Standard constructors: + static MenuOption Horizontal(); + static MenuOption HorizontalAnimated(); + static MenuOption Vertical(); + static MenuOption VerticalAnimated(); + static MenuOption Toggle(); + + ConstStringListRef entries; ///> The list of entries. + Ref selected = 0; ///> The index of the selected entry. + + // Style: + UnderlineOption underline; + MenuEntryOption entries_option; + Direction direction = Direction::Down; + std::function elements_prefix; + std::function elements_infix; + std::function elements_postfix; + + // Observers: + std::function on_change; ///> Called when the selected entry changes. + std::function on_enter; ///> Called when the user presses enter. + Ref focused_entry = 0; +}; + +/// @brief Option for the AnimatedButton component. +/// @ingroup component +struct ButtonOption { + // Standard constructors: + static ButtonOption Ascii(); + static ButtonOption Simple(); + static ButtonOption Border(); + static ButtonOption Animated(); + static ButtonOption Animated(Color color); + static ButtonOption Animated(Color background, Color foreground); + static ButtonOption Animated(Color background, + Color foreground, + Color background_active, + Color foreground_active); + + ConstStringRef label = "Button"; + std::function on_click = [] {}; + + // Style: + std::function transform; + AnimatedColorsOption animated_colors; +}; + +/// @brief Option for the Checkbox component. +/// @ingroup component +struct CheckboxOption { + // Standard constructors: + static CheckboxOption Simple(); + + ConstStringRef label = "Checkbox"; + + Ref checked = false; + + // Style: + std::function transform; + + // Observer: + /// Called when the user change the state. + std::function on_change = [] {}; +}; + +/// @brief Used to define style for the Input component. +struct InputState { + Element element; + bool hovered; /// < Whether the input is hovered by the mouse. + bool focused; /// < Whether the input is focused by the user. + bool is_placeholder; /// < Whether the input is empty and displaying the + /// < placeholder. +}; + +/// @brief Option for the Input component. +/// @ingroup component +struct InputOption { + // A set of predefined styles: + + /// @brief Create the default input style: + static InputOption Default(); + /// @brief A white on black style with high margins: + static InputOption Spacious(); + + /// The content of the input. + StringRef content = ""; + + /// The content of the input when it's empty. + StringRef placeholder = ""; + + // Style: + std::function transform; + Ref password = false; /// < Obscure the input content using '*'. + Ref multiline = true; /// < Whether the input can be multiline. + + /// Called when the content changes. + std::function on_change = [] {}; + /// Called when the user presses enter. + std::function on_enter = [] {}; + + // The char position of the cursor: + Ref cursor_position = 0; +}; + +/// @brief Option for the Radiobox component. +/// @ingroup component +struct RadioboxOption { + // Standard constructors: + static RadioboxOption Simple(); + + // Content: + ConstStringListRef entries; + Ref selected = 0; + + // Style: + std::function transform; + + // Observers: + /// Called when the selected entry changes. + std::function on_change = [] {}; + Ref focused_entry = 0; +}; + +struct ResizableSplitOption { + Component main; + Component back; + Ref direction = Direction::Left; + Ref main_size = + (direction() == Direction::Left || direction() == Direction::Right) ? 20 + : 10; + std::function separator_func = [] { return ::ftxui::separator(); }; +}; + +// @brief Option for the `Slider` component. +// @ingroup component +template +struct SliderOption { + Ref value; + ConstRef min = T(0); + ConstRef max = T(100); + ConstRef increment = (max() - min()) / 20; + Direction direction = Direction::Right; + Color color_active = Color::White; + Color color_inactive = Color::GrayDark; +}; + +// Parameter pack used by `WindowOptions::render`. +struct WindowRenderState { + Element inner; /// < The element wrapped inside this window. + const std::string& title; /// < The title of the window. + bool active = false; /// < Whether the window is the active one. + bool drag = false; /// < Whether the window is being dragged. + bool resize = false; /// < Whether the window is being resized. + bool hover_left = false; /// < Whether the resizeable left side is hovered. + bool hover_right = false; /// < Whether the resizeable right side is hovered. + bool hover_top = false; /// < Whether the resizeable top side is hovered. + bool hover_down = false; /// < Whether the resizeable down side is hovered. +}; + +// @brief Option for the `Window` component. +// @ingroup component +struct WindowOptions { + Component inner; /// < The component wrapped by this window. + ConstStringRef title = ""; /// < The title displayed by this window. + + Ref left = 0; /// < The left side position of the window. + Ref top = 0; /// < The top side position of the window. + Ref width = 20; /// < The width of the window. + Ref height = 10; /// < The height of the window. + + Ref resize_left = true; /// < Can the left side be resized? + Ref resize_right = true; /// < Can the right side be resized? + Ref resize_top = true; /// < Can the top side be resized? + Ref resize_down = true; /// < Can the down side be resized? + + /// An optional function to customize how the window looks like: + std::function render; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP */ diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp new file mode 100644 index 0000000..504bee0 --- /dev/null +++ b/include/ftxui/component/event.hpp @@ -0,0 +1,112 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_EVENT_HPP +#define FTXUI_COMPONENT_EVENT_HPP + +#include // for Mouse +#include +#include // for string, operator== +#include + +namespace ftxui { + +class ScreenInteractive; +class ComponentBase; + +/// @brief Represent an event. It can be key press event, a terminal resize, or +/// more ... +/// +/// For example: +/// - Printable character can be created using Event::Character('a'). +/// - Some special are predefined, like Event::ArrowLeft. +/// - One can find arbitrary code for special Events using: +/// ./example/util/print_key_press +/// For instance, CTLR+A maps to Event::Special({1}); +/// +/// Useful documentation about xterm specification: +/// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html +struct Event { + // --- Constructor section --------------------------------------------------- + static Event Character(std::string); + static Event Character(char); + static Event Character(wchar_t); + static Event Special(std::string); + static Event Mouse(std::string, Mouse mouse); + static Event CursorReporting(std::string, int x, int y); + + // --- Arrow --- + static const Event ArrowLeft; + static const Event ArrowRight; + static const Event ArrowUp; + static const Event ArrowDown; + + static const Event ArrowLeftCtrl; + static const Event ArrowRightCtrl; + static const Event ArrowUpCtrl; + static const Event ArrowDownCtrl; + + // --- Other --- + static const Event Backspace; + static const Event Delete; + static const Event Return; + static const Event Escape; + static const Event Tab; + static const Event TabReverse; + static const Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12; + + static const Event Home; + static const Event End; + + static const Event PageUp; + static const Event PageDown; + + // --- Custom --- + static const Event Custom; + + //--- Method section --------------------------------------------------------- + bool is_character() const { return type_ == Type::Character; } + std::string character() const { return input_; } + + bool is_mouse() const { return type_ == Type::Mouse; } + struct Mouse& mouse() { return data_.mouse; } + + bool is_cursor_reporting() const { return type_ == Type::CursorReporting; } + int cursor_x() const { return data_.cursor.x; } + int cursor_y() const { return data_.cursor.y; } + + const std::string& input() const { return input_; } + + bool operator==(const Event& other) const { return input_ == other.input_; } + bool operator!=(const Event& other) const { return !operator==(other); } + + //--- State section ---------------------------------------------------------- + ScreenInteractive* screen_ = nullptr; + + private: + friend ComponentBase; + friend ScreenInteractive; + enum class Type { + Unknown, + Character, + Mouse, + CursorReporting, + }; + Type type_ = Type::Unknown; + + struct Cursor { + int x = 0; + int y = 0; + }; + + union { + struct Mouse mouse; + struct Cursor cursor; + } data_ = {}; + + std::string input_; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_EVENT_HPP */ diff --git a/include/ftxui/component/loop.hpp b/include/ftxui/component/loop.hpp new file mode 100644 index 0000000..41b340c --- /dev/null +++ b/include/ftxui/component/loop.hpp @@ -0,0 +1,38 @@ +// Copyright 2022 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_LOOP_HPP +#define FTXUI_COMPONENT_LOOP_HPP + +#include // for shared_ptr + +#include "ftxui/component/component_base.hpp" // for ComponentBase + +namespace ftxui { +class ComponentBase; + +using Component = std::shared_ptr; +class ScreenInteractive; + +class Loop { + public: + Loop(ScreenInteractive* screen, Component component); + ~Loop(); + + bool HasQuitted(); + void RunOnce(); + void RunOnceBlocking(); + void Run(); + + private: + // This class is non copyable. + Loop(const ScreenInteractive&) = delete; + Loop& operator=(const Loop&) = delete; + + ScreenInteractive* screen_; + Component component_; +}; + +} // namespace ftxui + +#endif // FTXUI_COMPONENT_LOOP_HPP diff --git a/include/ftxui/component/mouse.hpp b/include/ftxui/component/mouse.hpp new file mode 100644 index 0000000..3c61008 --- /dev/null +++ b/include/ftxui/component/mouse.hpp @@ -0,0 +1,44 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_MOUSE_HPP +#define FTXUI_COMPONENT_MOUSE_HPP +namespace ftxui { + +/// @brief A mouse event. It contains the coordinate of the mouse, the button +/// pressed and the modifier (shift, ctrl, meta). +/// @ingroup component +struct Mouse { + enum Button { + Left = 0, + Middle = 1, + Right = 2, + None = 3, + WheelUp = 4, + WheelDown = 5, + }; + + enum Motion { + Released = 0, + Pressed = 1, + }; + + // Button + Button button = Button::None; + + // Motion + Motion motion = Motion::Pressed; + + // Modifiers: + bool shift = false; + bool meta = false; + bool control = false; + + // Coordinates: + int x = 0; + int y = 0; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_MOUSE_HPP */ diff --git a/include/ftxui/component/receiver.hpp b/include/ftxui/component/receiver.hpp new file mode 100644 index 0000000..95f2353 --- /dev/null +++ b/include/ftxui/component/receiver.hpp @@ -0,0 +1,140 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_RECEIVER_HPP_ +#define FTXUI_COMPONENT_RECEIVER_HPP_ + +#include // for copy, max +#include // for atomic, __atomic_base +#include // for condition_variable +#include +#include +#include // for unique_ptr, make_unique +#include // for mutex, unique_lock +#include // for queue +#include // for move + +namespace ftxui { + +// Usage: +// +// Initialization: +// --------------- +// +// auto receiver = MakeReceiver(); +// auto sender_1= receiver->MakeSender(); +// auto sender_2 = receiver->MakeSender(); +// +// Then move the senders elsewhere, potentially in a different thread. +// +// On the producer side: +// ---------------------- +// [thread 1] sender_1->Send("hello"); +// [thread 2] sender_2->Send("world"); +// +// On the consumer side: +// --------------------- +// char c; +// while(receiver->Receive(&c)) // Return true as long as there is a producer. +// print(c) +// +// Receiver::Receive() returns true when there are no more senders. + +// clang-format off +template class SenderImpl; +template class ReceiverImpl; + +template using Sender = std::unique_ptr>; +template using Receiver = std::unique_ptr>; +template Receiver MakeReceiver(); +// clang-format on + +// ---- Implementation part ---- + +template +class SenderImpl { + public: + void Send(T t) { receiver_->Receive(std::move(t)); } + ~SenderImpl() { receiver_->ReleaseSender(); } + + Sender Clone() { return receiver_->MakeSender(); } + + private: + friend class ReceiverImpl; + SenderImpl(ReceiverImpl* consumer) : receiver_(consumer) {} + ReceiverImpl* receiver_; +}; + +template +class ReceiverImpl { + public: + Sender MakeSender() { + std::unique_lock lock(mutex_); + senders_++; + return std::unique_ptr>(new SenderImpl(this)); + } + ReceiverImpl() { senders_ = 0; } + + bool Receive(T* t) { + while (senders_ || !queue_.empty()) { + std::unique_lock 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 lock(mutex_); + if (queue_.empty()) + return false; + *t = queue_.front(); + queue_.pop(); + return true; + } + + bool HasPending() { + std::unique_lock lock(mutex_); + return !queue_.empty(); + } + + bool HasQuitted() { + std::unique_lock lock(mutex_); + return queue_.empty() && !senders_; + } + + private: + friend class SenderImpl; + + void Receive(T t) { + { + std::unique_lock lock(mutex_); + queue_.push(std::move(t)); + } + notifier_.notify_one(); + } + + void ReleaseSender() { + senders_--; + notifier_.notify_one(); + } + + std::mutex mutex_; + std::queue queue_; + std::condition_variable notifier_; + std::atomic senders_; +}; + +template +Receiver MakeReceiver() { + return std::make_unique>(); +} + +} // namespace ftxui + +#endif // FTXUI_COMPONENT_RECEIVER_HPP_ diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp new file mode 100644 index 0000000..10d022c --- /dev/null +++ b/include/ftxui/component/screen_interactive.hpp @@ -0,0 +1,127 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP +#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP + +#include // for atomic +#include // for Receiver, Sender +#include // for function +#include // for shared_ptr +#include // for string +#include // for thread +#include // for variant + +#include "ftxui/component/animation.hpp" // for TimePoint +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/event.hpp" // for Event +#include "ftxui/component/task.hpp" // for Task, Closure +#include "ftxui/screen/screen.hpp" // for Screen + +namespace ftxui { +class ComponentBase; +class Loop; +struct Event; + +using Component = std::shared_ptr; +class ScreenInteractivePrivate; + +class ScreenInteractive : public Screen { + public: + // Constructors: + static ScreenInteractive FixedSize(int dimx, int dimy); + static ScreenInteractive Fullscreen(); + static ScreenInteractive FitComponent(); + static ScreenInteractive TerminalOutput(); + + // Options. Must be called before Loop(). + void TrackMouse(bool enable = true); + + // Return the currently active screen, nullptr if none. + static ScreenInteractive* Active(); + + // Start/Stop the main loop. + void Loop(Component); + void Exit(); + Closure ExitLoopClosure(); + + // Post tasks to be executed by the loop. + void Post(Task task); + void PostEvent(Event event); + void RequestAnimationFrame(); + + CapturedMouse CaptureMouse(); + + // Decorate a function. The outputted one will execute similarly to the + // inputted one, but with the currently active screen terminal hooks + // temporarily uninstalled. + Closure WithRestoredIO(Closure); + + private: + void ExitNow(); + + void Install(); + void Uninstall(); + + void PreMain(); + void PostMain(); + + bool HasQuitted(); + void RunOnce(Component component); + void RunOnceBlocking(Component component); + + void HandleTask(Component component, Task& task); + void Draw(Component component); + void ResetCursorPosition(); + + void Signal(int signal); + + ScreenInteractive* suspended_screen_ = nullptr; + enum class Dimension { + FitComponent, + Fixed, + Fullscreen, + TerminalOutput, + }; + Dimension dimension_ = Dimension::Fixed; + bool use_alternative_screen_ = false; + ScreenInteractive(int dimx, + int dimy, + Dimension dimension, + bool use_alternative_screen); + + bool track_mouse_ = true; + + Sender task_sender_; + Receiver task_receiver_; + + std::string set_cursor_position; + std::string reset_cursor_position; + + std::atomic quit_ = false; + std::thread event_listener_; + std::thread animation_listener_; + bool animation_requested_ = false; + animation::TimePoint previous_animation_time_; + + int cursor_x_ = 1; + int cursor_y_ = 1; + + bool mouse_captured = false; + bool previous_frame_resized_ = false; + + bool frame_valid_ = false; + + friend class Loop; + + public: + class Private { + public: + static void Signal(ScreenInteractive& s, int signal) { s.Signal(signal); } + }; + friend Private; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP */ diff --git a/include/ftxui/component/task.hpp b/include/ftxui/component/task.hpp new file mode 100644 index 0000000..6a770e8 --- /dev/null +++ b/include/ftxui/component/task.hpp @@ -0,0 +1,17 @@ +// Copyright 2022 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_COMPONENT_ANIMATION_HPP +#define FTXUI_COMPONENT_ANIMATION_HPP + +#include +#include +#include "ftxui/component/event.hpp" + +namespace ftxui { +class AnimationTask {}; +using Closure = std::function; +using Task = std::variant; +} // namespace ftxui + +#endif // FTXUI_COMPONENT_ANIMATION_HPP diff --git a/include/ftxui/dom/canvas.hpp b/include/ftxui/dom/canvas.hpp new file mode 100644 index 0000000..9286838 --- /dev/null +++ b/include/ftxui/dom/canvas.hpp @@ -0,0 +1,138 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_CANVAS_HPP +#define FTXUI_DOM_CANVAS_HPP + +#include // for size_t +#include // for function +#include // for string +#include // for unordered_map + +#include "ftxui/screen/color.hpp" // for Color +#include "ftxui/screen/screen.hpp" // for Pixel + +#ifdef DrawText +// Workaround for WinUsr.h (via Windows.h) defining macros that break things. +// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawtext +#undef DrawText +#endif + +namespace ftxui { + +struct Canvas { + public: + Canvas() = default; + Canvas(int width, int height); + + // Getters: + int width() const { return width_; } + int height() const { return height_; } + Pixel GetPixel(int x, int y) const; + + using Stylizer = std::function; + + // Draws using braille characters -------------------------------------------- + void DrawPointOn(int x, int y); + void DrawPointOff(int x, int y); + void DrawPointToggle(int x, int y); + void DrawPoint(int x, int y, bool value); + void DrawPoint(int x, int y, bool value, const Stylizer& s); + void DrawPoint(int x, int y, bool value, const Color& color); + void DrawPointLine(int x1, int y1, int x2, int y2); + void DrawPointLine(int x1, int y1, int x2, int y2, const Stylizer& s); + void DrawPointLine(int x1, int y1, int x2, int y2, const Color& color); + void DrawPointCircle(int x, int y, int radius); + void DrawPointCircle(int x, int y, int radius, const Stylizer& s); + void DrawPointCircle(int x, int y, int radius, const Color& color); + void DrawPointCircleFilled(int x, int y, int radius); + void DrawPointCircleFilled(int x, int y, int radius, const Stylizer& s); + void DrawPointCircleFilled(int x, int y, int radius, const Color& color); + void DrawPointEllipse(int x, int y, int r1, int r2); + void DrawPointEllipse(int x, int y, int r1, int r2, const Color& color); + void DrawPointEllipse(int x, int y, int r1, int r2, const Stylizer& s); + void DrawPointEllipseFilled(int x, int y, int r1, int r2); + void DrawPointEllipseFilled(int x, int y, int r1, int r2, const Color& color); + void DrawPointEllipseFilled(int x, int y, int r1, int r2, const Stylizer& s); + + // Draw using box characters ------------------------------------------------- + // Block are of size 1x2. y is considered to be a multiple of 2. + void DrawBlockOn(int x, int y); + void DrawBlockOff(int x, int y); + void DrawBlockToggle(int x, int y); + void DrawBlock(int x, int y, bool value); + void DrawBlock(int x, int y, bool value, const Stylizer& s); + void DrawBlock(int x, int y, bool value, const Color& color); + void DrawBlockLine(int x1, int y1, int x2, int y2); + void DrawBlockLine(int x1, int y1, int x2, int y2, const Stylizer& s); + void DrawBlockLine(int x1, int y1, int x2, int y2, const Color& color); + void DrawBlockCircle(int x1, int y1, int radius); + void DrawBlockCircle(int x1, int y1, int radius, const Stylizer& s); + void DrawBlockCircle(int x1, int y1, int radius, const Color& color); + void DrawBlockCircleFilled(int x1, int y1, int radius); + void DrawBlockCircleFilled(int x1, int y1, int radius, const Stylizer& s); + void DrawBlockCircleFilled(int x1, int y1, int radius, const Color& color); + void DrawBlockEllipse(int x1, int y1, int r1, int r2); + void DrawBlockEllipse(int x1, int y1, int r1, int r2, const Stylizer& s); + void DrawBlockEllipse(int x1, int y1, int r1, int r2, const Color& color); + void DrawBlockEllipseFilled(int x1, int y1, int r1, int r2); + void DrawBlockEllipseFilled(int x1, + int y1, + int r1, + int r2, + const Stylizer& s); + void DrawBlockEllipseFilled(int x1, + int y1, + int r1, + int r2, + const Color& color); + + // Draw using normal characters ---------------------------------------------- + // Draw using character of size 2x4 at position (x,y) + // x is considered to be a multiple of 2. + // y is considered to be a multiple of 4. + void DrawText(int x, int y, const std::string& value); + void DrawText(int x, int y, const std::string& value, const Color& color); + void DrawText(int x, int y, const std::string& value, const Stylizer& style); + + // Decorator: + // x is considered to be a multiple of 2. + // y is considered to be a multiple of 4. + void Style(int x, int y, const Stylizer& style); + + private: + bool IsIn(int x, int y) const { + return x >= 0 && x < width_ && y >= 0 && y < height_; + } + enum CellType { + kBraille, + kBlock, + kText, + }; + struct Cell { + CellType type = kText; + Pixel content; + }; + struct XY { + int x; + int y; + bool operator==(const XY& other) const { + return x == other.x && y == other.y; + } + }; + + struct XYHash { + size_t operator()(const XY& xy) const { + constexpr size_t shift = 1024; + return size_t(xy.x) * shift + size_t(xy.y); + } + }; + + int width_ = 0; + int height_ = 0; + std::unordered_map storage_; +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_CANVAS_HPP diff --git a/include/ftxui/dom/deprecated.hpp b/include/ftxui/dom/deprecated.hpp new file mode 100644 index 0000000..f4faf8d --- /dev/null +++ b/include/ftxui/dom/deprecated.hpp @@ -0,0 +1,15 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_DEPRECATED_HPP +#define FTXUI_DOM_DEPRECATED_HPP + +#include "ftxui/dom/elements.hpp" + +namespace ftxui { +Element text(std::wstring text); +Element vtext(std::wstring text); +Elements paragraph(std::wstring text); +} // namespace ftxui + +#endif // FTXUI_DOM_DEPRECATED_HPP diff --git a/include/ftxui/dom/direction.hpp b/include/ftxui/dom/direction.hpp new file mode 100644 index 0000000..2a38f09 --- /dev/null +++ b/include/ftxui/dom/direction.hpp @@ -0,0 +1,17 @@ +// Copyright 2023 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_DIRECTION_HPP +#define FTXUI_DOM_DIRECTION_HPP + +namespace ftxui { +enum class Direction { + Up = 0, + Down = 1, + Left = 2, + Right = 3, +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_DOM_DIRECTION_HPP */ diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp new file mode 100644 index 0000000..ffd9360 --- /dev/null +++ b/include/ftxui/dom/elements.hpp @@ -0,0 +1,196 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_ELEMENTS_HPP +#define FTXUI_DOM_ELEMENTS_HPP + +#include +#include + +#include "ftxui/dom/canvas.hpp" +#include "ftxui/dom/direction.hpp" +#include "ftxui/dom/flexbox_config.hpp" +#include "ftxui/dom/linear_gradient.hpp" +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" +#include "ftxui/screen/screen.hpp" +#include "ftxui/screen/terminal.hpp" +#include "ftxui/util/ref.hpp" + +namespace ftxui { +class Node; +using Element = std::shared_ptr; +using Elements = std::vector; +using Decorator = std::function; +using GraphFunction = std::function(int, int)>; + +enum BorderStyle { + LIGHT, + DASHED, + HEAVY, + DOUBLE, + ROUNDED, + EMPTY, +}; + +// Pipe elements into decorator togethers. +// For instance the next lines are equivalents: +// -> text("ftxui") | bold | underlined +// -> underlined(bold(text("FTXUI"))) +Element operator|(Element, Decorator); +Element& operator|=(Element&, Decorator); +Elements operator|(Elements, Decorator); +Decorator operator|(Decorator, Decorator); + +// --- Widget --- +Element text(std::string text); +Element vtext(std::string text); +Element separator(); +Element separatorLight(); +Element separatorDashed(); +Element separatorHeavy(); +Element separatorDouble(); +Element separatorEmpty(); +Element separatorStyled(BorderStyle); +Element separator(Pixel); +Element separatorCharacter(std::string); +Element separatorHSelector(float left, + float right, + Color unselected_color, + Color selected_color); +Element separatorVSelector(float up, + float down, + Color unselected_color, + Color selected_color); +Element gauge(float progress); +Element gaugeLeft(float progress); +Element gaugeRight(float progress); +Element gaugeUp(float progress); +Element gaugeDown(float progress); +Element gaugeDirection(float progress, Direction direction); +Element border(Element); +Element borderLight(Element); +Element borderDashed(Element); +Element borderHeavy(Element); +Element borderDouble(Element); +Element borderRounded(Element); +Element borderEmpty(Element); +Decorator borderStyled(BorderStyle); +Decorator borderStyled(BorderStyle, Color); +Decorator borderStyled(Color); +Decorator borderWith(const Pixel&); +Element window(Element title, Element content); +Element spinner(int charset_index, size_t image_index); +Element paragraph(const std::string& text); +Element paragraphAlignLeft(const std::string& text); +Element paragraphAlignRight(const std::string& text); +Element paragraphAlignCenter(const std::string& text); +Element paragraphAlignJustify(const std::string& text); +Element graph(GraphFunction); +Element emptyElement(); +Element canvas(ConstRef); +Element canvas(int width, int height, std::function); +Element canvas(std::function); + +// -- Decorator --- +Element bold(Element); +Element dim(Element); +Element inverted(Element); +Element underlined(Element); +Element underlinedDouble(Element); +Element blink(Element); +Element strikethrough(Element); +Decorator color(Color); +Decorator bgcolor(Color); +Decorator color(const LinearGradient&); +Decorator bgcolor(const LinearGradient&); +Element color(Color, Element); +Element bgcolor(Color, Element); +Element color(const LinearGradient&, Element); +Element bgcolor(const LinearGradient&, Element); +Decorator focusPosition(int x, int y); +Decorator focusPositionRelative(float x, float y); +Element automerge(Element child); +Decorator hyperlink(std::string link); +Element hyperlink(std::string link, Element child); + +// --- Layout is +// Horizontal, Vertical or stacked set of elements. +Element hbox(Elements); +Element vbox(Elements); +Element dbox(Elements); +Element flexbox(Elements, FlexboxConfig config = FlexboxConfig()); +Element gridbox(std::vector lines); + +Element hflow(Elements); // Helper: default flexbox with row direction. +Element vflow(Elements); // Helper: default flexbox with column direction. + +// -- Flexibility --- +// Define how to share the remaining space when not all of it is used inside a +// container. +Element flex(Element); // Expand/Minimize if possible/needed. +Element flex_grow(Element); // Expand element if possible. +Element flex_shrink(Element); // Minimize element if needed. + +Element xflex(Element); // Expand/Minimize if possible/needed on X axis. +Element xflex_grow(Element); // Expand element if possible on X axis. +Element xflex_shrink(Element); // Minimize element if needed on X axis. + +Element yflex(Element); // Expand/Minimize if possible/needed on Y axis. +Element yflex_grow(Element); // Expand element if possible on Y axis. +Element yflex_shrink(Element); // Minimize element if needed on Y axis. + +Element notflex(Element); // Reset the flex attribute. +Element filler(); // A blank expandable element. + +// -- Size override; +enum WidthOrHeight { WIDTH, HEIGHT }; +enum Constraint { LESS_THAN, EQUAL, GREATER_THAN }; +Decorator size(WidthOrHeight, Constraint, int value); + +// --- Frame --- +// A frame is a scrollable area. The internal area is potentially larger than +// the external one. The internal area is scrolled in order to make visible the +// focused element. +Element frame(Element); +Element xframe(Element); +Element yframe(Element); +Element focus(Element); +Element select(Element); + +// --- Cursor --- +// Those are similar to `focus`, but also change the shape of the cursor. +Element focusCursorBlock(Element); +Element focusCursorBlockBlinking(Element); +Element focusCursorBar(Element); +Element focusCursorBarBlinking(Element); +Element focusCursorUnderline(Element); +Element focusCursorUnderlineBlinking(Element); + +// --- Misc --- +Element vscroll_indicator(Element); +Decorator reflect(Box& box); +// Before drawing the |element| clear the pixel below. This is useful in +// combinaison with dbox. +Element clear_under(Element element); + +// --- Util -------------------------------------------------------------------- +Element hcenter(Element); +Element vcenter(Element); +Element center(Element); +Element align_right(Element); +Element nothing(Element element); + +namespace Dimension { +Dimensions Fit(Element&); +} // namespace Dimension + +} // namespace ftxui + +// Make container able to take any number of children as input. +#include "ftxui/dom/take_any_args.hpp" + +// Include old definitions using wstring. +#include "ftxui/dom/deprecated.hpp" +#endif // FTXUI_DOM_ELEMENTS_HPP diff --git a/include/ftxui/dom/flexbox_config.hpp b/include/ftxui/dom/flexbox_config.hpp new file mode 100644 index 0000000..8ae2677 --- /dev/null +++ b/include/ftxui/dom/flexbox_config.hpp @@ -0,0 +1,114 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_FLEXBOX_CONFIG_HPP +#define FTXUI_DOM_FLEXBOX_CONFIG_HPP + +/* + This replicate the CSS flexbox model. + See guide for documentation: + https://css-tricks.com/snippets/css/a-guide-to-flexbox/ +*/ + +namespace ftxui { + +struct FlexboxConfig { + /// This establishes the main-axis, thus defining the direction flex items are + /// placed in the flex container. Flexbox is (aside wrapping) single-direction + /// layout concept. Think of flex items as primarily laying out either in + /// horizontal rows or vertical columns. + enum class Direction { + Row, ///< Flex items are laid out in a row. + RowInversed, ///< Flex items are laid out in a row, but in reverse order. + Column, ///< Flex items are laid out in a column. + ColumnInversed ///< Flex items are laid out in a column, but in reverse + ///< order. + }; + Direction direction = Direction::Row; + + /// By default, flex items will all try to fit onto one line. You can change + /// that and allow the items to wrap as needed with this property. + enum class Wrap { + NoWrap, ///< Flex items will all try to fit onto one line. + Wrap, ///< Flex items will wrap onto multiple lines. + WrapInversed, ///< Flex items will wrap onto multiple lines, but in reverse + ///< order. + }; + Wrap wrap = Wrap::Wrap; + + /// This defines the alignment along the main axis. It helps distribute extra + /// free space leftover when either all the flex items on a line are + /// inflexible, or are flexible but have reached their maximum size. It also + /// exerts some control over the alignment of items when they overflow the + /// line. + enum class JustifyContent { + /// Items are aligned to the start of flexbox's direction. + FlexStart, + /// Items are aligned to the end of flexbox's direction. + FlexEnd, + /// Items are centered along the line. + Center, + /// Items are stretched to fill the line. + Stretch, + /// Items are evenly distributed in the line; first item is on the start + // line, last item on the end line + SpaceBetween, + /// Items are evenly distributed in the line with equal space around them. + /// Note that visually the spaces aren’t equal, since all the items have + /// equal space on both sides. The first item will have one unit of space + /// against the container edge, but two units of space between the next item + /// because that next item has its own spacing that applies. + SpaceAround, + /// Items are distributed so that the spacing between any two items (and the + /// space to the edges) is equal. + SpaceEvenly, + }; + JustifyContent justify_content = JustifyContent::FlexStart; + + /// This defines the default behavior for how flex items are laid out along + /// the cross axis on the current line. Think of it as the justify-content + /// version for the cross-axis (perpendicular to the main-axis). + enum class AlignItems { + FlexStart, ///< items are placed at the start of the cross axis. + FlexEnd, ///< items are placed at the end of the cross axis. + Center, ///< items are centered along the cross axis. + Stretch, ///< items are stretched to fill the cross axis. + }; + AlignItems align_items = AlignItems::FlexStart; + + // This aligns a flex container’s lines within when there is extra space in + // the cross-axis, similar to how justify-content aligns individual items + // within the main-axis. + enum class AlignContent { + FlexStart, ///< items are placed at the start of the cross axis. + FlexEnd, ///< items are placed at the end of the cross axis. + Center, ///< items are centered along the cross axis. + Stretch, ///< items are stretched to fill the cross axis. + SpaceBetween, ///< items are evenly distributed in the cross axis. + SpaceAround, ///< tems evenly distributed with equal space around each + ///< line. + SpaceEvenly, ///< items are evenly distributed in the cross axis with equal + ///< space around them. + }; + AlignContent align_content = AlignContent::FlexStart; + + int gap_x = 0; + int gap_y = 0; + + // Constructor pattern. For chained use like: + // ``` + // FlexboxConfig() + // .Set(FlexboxConfig::Direction::Row) + // .Set(FlexboxConfig::Wrap::Wrap); + // ``` + FlexboxConfig& Set(FlexboxConfig::Direction); + FlexboxConfig& Set(FlexboxConfig::Wrap); + FlexboxConfig& Set(FlexboxConfig::JustifyContent); + FlexboxConfig& Set(FlexboxConfig::AlignItems); + FlexboxConfig& Set(FlexboxConfig::AlignContent); + FlexboxConfig& SetGap(int gap_x, int gap_y); +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_FLEXBOX_CONFIG_HPP diff --git a/include/ftxui/dom/linear_gradient.hpp b/include/ftxui/dom/linear_gradient.hpp new file mode 100644 index 0000000..da7e77b --- /dev/null +++ b/include/ftxui/dom/linear_gradient.hpp @@ -0,0 +1,51 @@ +// Copyright 2023 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_LINEAR_GRADIENT_HPP +#define FTXUI_DOM_LINEAR_GRADIENT_HPP + +#include +#include + +#include "ftxui/screen/color.hpp" // for Colors + +namespace ftxui { + +/// @brief A class representing the settings for linear-gradient color effect. +/// +/// Example: +/// ```cpp +/// LinearGradient() +/// .Angle(45) +/// .Stop(Color::Red, 0.0) +/// .Stop(Color::Green, 0.5) +/// .Stop(Color::Blue, 1.0); +/// ``` +/// +/// There are also shorthand constructors: +/// ```cpp +/// LinearGradient(Color::Red, Color::Blue); +/// LinearGradient(45, Color::Red, Color::Blue); +/// ``` +struct LinearGradient { + float angle = 0.f; + struct Stop { + Color color = Color::Default; + std::optional position; + }; + std::vector stops; + + // Simple constructor + LinearGradient(); + LinearGradient(Color begin, Color end); + LinearGradient(float angle, Color begin, Color end); + + // Modifier using the builder pattern. + LinearGradient& Angle(float angle); + LinearGradient& Stop(Color color, float position); + LinearGradient& Stop(Color color); +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_LINEAR_GRADIENT_HPP diff --git a/include/ftxui/dom/node.hpp b/include/ftxui/dom/node.hpp new file mode 100644 index 0000000..a462b0a --- /dev/null +++ b/include/ftxui/dom/node.hpp @@ -0,0 +1,66 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_NODE_HPP +#define FTXUI_DOM_NODE_HPP + +#include // for shared_ptr +#include // for vector + +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/screen.hpp" + +namespace ftxui { + +class Node; +class Screen; + +using Element = std::shared_ptr; +using Elements = std::vector; + +class Node { + public: + Node(); + Node(Elements children); + Node(const Node&) = delete; + Node(const Node&&) = delete; + Node& operator=(const Node&) = delete; + Node& operator=(const Node&&) = delete; + + virtual ~Node(); + + // Step 1: Compute layout requirement. Tell parent what dimensions this + // element wants to be. + // Propagated from Children to Parents. + virtual void ComputeRequirement(); + Requirement requirement() { return requirement_; } + + // Step 2: Assign this element its final dimensions. + // Propagated from Parents to Children. + virtual void SetBox(Box box); + + // Step 3: Draw this element. + virtual void Render(Screen& screen); + + // Layout may not resolve within a single iteration for some elements. This + // allows them to request additionnal iterations. This signal must be + // forwarded to children at least once. + struct Status { + int iteration = 0; + bool need_iteration = false; + }; + virtual void Check(Status* status); + + protected: + Elements children_; + Requirement requirement_; + Box box_; +}; + +void Render(Screen& screen, const Element& element); +void Render(Screen& screen, Node* node); + +} // namespace ftxui + +#endif // FTXUI_DOM_NODE_HPP diff --git a/include/ftxui/dom/requirement.hpp b/include/ftxui/dom/requirement.hpp new file mode 100644 index 0000000..1b0a884 --- /dev/null +++ b/include/ftxui/dom/requirement.hpp @@ -0,0 +1,34 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_REQUIREMENT_HPP +#define FTXUI_DOM_REQUIREMENT_HPP + +#include "ftxui/screen/box.hpp" + +namespace ftxui { + +struct Requirement { + // The required size to fully draw the element. + int min_x = 0; + int min_y = 0; + + // How much flexibility is given to the component. + int flex_grow_x = 0; + int flex_grow_y = 0; + int flex_shrink_x = 0; + int flex_shrink_y = 0; + + // Focus management to support the frame/focus/select element. + enum Selection { + NORMAL = 0, + SELECTED = 1, + FOCUSED = 2, + }; + Selection selection = NORMAL; + Box selected_box; +}; + +} // namespace ftxui + +#endif // FTXUI_DOM_REQUIREMENT_HPP diff --git a/include/ftxui/dom/table.hpp b/include/ftxui/dom/table.hpp new file mode 100644 index 0000000..5b7fd34 --- /dev/null +++ b/include/ftxui/dom/table.hpp @@ -0,0 +1,95 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_TABLE +#define FTXUI_DOM_TABLE + +#include +#include // for string +#include // for vector + +#include "ftxui/dom/elements.hpp" // for Element, BorderStyle, LIGHT, Decorator + +namespace ftxui { + +// Usage: +// +// Initialization: +// --------------- +// +// auto table = Table({ +// {"X", "Y"}, +// {"-1", "1"}, +// {"+0", "0"}, +// {"+1", "1"}, +// }); +// +// table.SelectAll().Border(LIGHT); +// +// table.SelectRow(1).Border(DOUBLE); +// table.SelectRow(1).SeparatorInternal(Light); +// +// std::move(table).Element(); + +class Table; +class TableSelection; + +class Table { + public: + Table(); + Table(std::vector>); + Table(std::vector>); + TableSelection SelectAll(); + TableSelection SelectCell(int column, int row); + TableSelection SelectRow(int row_index); + TableSelection SelectRows(int row_min, int row_max); + TableSelection SelectColumn(int column_index); + TableSelection SelectColumns(int column_min, int column_max); + TableSelection SelectRectangle(int column_min, + int column_max, + int row_min, + int row_max); + Element Render(); + + private: + void Initialize(std::vector>); + friend TableSelection; + std::vector> elements_; + int input_dim_x_ = 0; + int input_dim_y_ = 0; + int dim_x_ = 0; + int dim_y_ = 0; +}; + +class TableSelection { + public: + void Decorate(Decorator); + void DecorateAlternateRow(Decorator, int modulo = 2, int shift = 0); + void DecorateAlternateColumn(Decorator, int modulo = 2, int shift = 0); + + void DecorateCells(Decorator); + void DecorateCellsAlternateColumn(Decorator, int modulo = 2, int shift = 0); + void DecorateCellsAlternateRow(Decorator, int modulo = 2, int shift = 0); + + void Border(BorderStyle border = LIGHT); + void BorderLeft(BorderStyle border = LIGHT); + void BorderRight(BorderStyle border = LIGHT); + void BorderTop(BorderStyle border = LIGHT); + void BorderBottom(BorderStyle border = LIGHT); + + void Separator(BorderStyle border = LIGHT); + void SeparatorVertical(BorderStyle border = LIGHT); + void SeparatorHorizontal(BorderStyle border = LIGHT); + + private: + friend Table; + Table* table_; + int x_min_; + int x_max_; + int y_min_; + int y_max_; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_DOM_TABLE */ diff --git a/include/ftxui/dom/take_any_args.hpp b/include/ftxui/dom/take_any_args.hpp new file mode 100644 index 0000000..79491ef --- /dev/null +++ b/include/ftxui/dom/take_any_args.hpp @@ -0,0 +1,47 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_DOM_TAKE_ANY_ARGS_HPP +#define FTXUI_DOM_TAKE_ANY_ARGS_HPP + +// IWYU pragma: private, include "ftxui/dom/elements.hpp" +#include + +namespace ftxui { + +template +void Merge(Elements& /*container*/, T /*element*/) {} + +template <> +inline void Merge(Elements& container, Element element) { + container.push_back(std::move(element)); +} + +template <> +inline void Merge(Elements& container, Elements elements) { + for (auto& element : elements) + container.push_back(std::move(element)); +} + +// Turn a set of arguments into a vector. +template +Elements unpack(Args... args) { + std::vector vec; + (Merge(vec, std::move(args)), ...); + return vec; +} + +// Make |container| able to take any number of argments. +#define TAKE_ANY_ARGS(container) \ + template \ + Element container(Args... children) { \ + return container(unpack(std::forward(children)...)); \ + } + +TAKE_ANY_ARGS(vbox) +TAKE_ANY_ARGS(hbox) +TAKE_ANY_ARGS(dbox) +TAKE_ANY_ARGS(hflow) +} // namespace ftxui + +#endif // FTXUI_DOM_TAKE_ANY_ARGS_HPP diff --git a/include/ftxui/screen/box.hpp b/include/ftxui/screen/box.hpp new file mode 100644 index 0000000..701b600 --- /dev/null +++ b/include/ftxui/screen/box.hpp @@ -0,0 +1,24 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_BOX_HPP +#define FTXUI_SCREEN_BOX_HPP + +namespace ftxui { + +struct Box { + int x_min = 0; + int x_max = 0; + int y_min = 0; + int y_max = 0; + + static auto Intersection(Box a, Box b) -> Box; + static auto Union(Box a, Box b) -> Box; + bool Contain(int x, int y) const; + bool operator==(const Box& other) const; + bool operator!=(const Box& other) const; +}; + +} // namespace ftxui + +#endif // FTXUI_SCREEN_BOX_HPP diff --git a/include/ftxui/screen/color.hpp b/include/ftxui/screen/color.hpp new file mode 100644 index 0000000..8939e50 --- /dev/null +++ b/include/ftxui/screen/color.hpp @@ -0,0 +1,336 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_COLOR_HPP +#define FTXUI_SCREEN_COLOR_HPP + +#include // for uint8_t +#include // for string +#include // for vector + +#ifdef RGB +// Workaround for wingdi.h (via Windows.h) defining macros that break things. +// https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-rgb +#undef RGB +#endif + +namespace ftxui { + +/// @brief A class representing terminal colors. +/// @ingroup screen +class Color { + public: + enum Palette1 : uint8_t; + enum Palette16 : uint8_t; + enum Palette256 : uint8_t; + + Color(); // Transparent. + Color(Palette1 index); // Transparent. + Color(Palette16 index); // Implicit conversion from index to Color. + Color(Palette256 index); // Implicit conversion from index to 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: + //--------------------------- + // clang-format off + enum Palette1 : uint8_t{ + Default, // Transparent + }; + + enum Palette16 : uint8_t { + Black = 0, + Red = 1, + Green = 2, + Yellow = 3, + Blue = 4, + Magenta = 5, + Cyan = 6, + GrayLight = 7, + GrayDark = 8, + RedLight = 9, + GreenLight = 10, + YellowLight = 11, + BlueLight = 12, + MagentaLight = 13, + CyanLight = 14, + White = 15, + }; + + enum Palette256 : uint8_t { + Aquamarine1 = 122, + Aquamarine1Bis = 86, + Aquamarine3 = 79, + Blue1 = 21, + Blue3 = 19, + Blue3Bis = 20, + BlueViolet = 57, + CadetBlue = 72, + CadetBlueBis = 73, + Chartreuse1 = 118, + Chartreuse2 = 112, + Chartreuse2Bis = 82, + Chartreuse3 = 70, + Chartreuse3Bis = 76, + Chartreuse4 = 64, + CornflowerBlue = 69, + Cornsilk1 = 230, + Cyan1 = 51, + Cyan2 = 50, + Cyan3 = 43, + DarkBlue = 18, + DarkCyan = 36, + DarkGoldenrod = 136, + DarkGreen = 22, + DarkKhaki = 143, + DarkMagenta = 90, + DarkMagentaBis = 91, + DarkOliveGreen1 = 191, + DarkOliveGreen1Bis = 192, + DarkOliveGreen2 = 155, + DarkOliveGreen3 = 107, + DarkOliveGreen3Bis = 113, + DarkOliveGreen3Ter = 149, + DarkOrange = 208, + DarkOrange3 = 130, + DarkOrange3Bis = 166, + DarkRed = 52, + DarkRedBis = 88, + DarkSeaGreen = 108, + DarkSeaGreen1 = 158, + DarkSeaGreen1Bis = 193, + DarkSeaGreen2 = 151, + DarkSeaGreen2Bis = 157, + DarkSeaGreen3 = 115, + DarkSeaGreen3Bis = 150, + DarkSeaGreen4 = 65, + DarkSeaGreen4Bis = 71, + DarkSlateGray1 = 123, + DarkSlateGray2 = 87, + DarkSlateGray3 = 116, + DarkTurquoise = 44, + DarkViolet = 128, + DarkVioletBis = 92, + DeepPink1 = 198, + DeepPink1Bis = 199, + DeepPink2 = 197, + DeepPink3 = 161, + DeepPink3Bis = 162, + DeepPink4 = 125, + DeepPink4Bis = 89, + DeepPink4Ter = 53, + DeepSkyBlue1 = 39, + DeepSkyBlue2 = 38, + DeepSkyBlue3 = 31, + DeepSkyBlue3Bis = 32, + DeepSkyBlue4 = 23, + DeepSkyBlue4Bis = 24, + DeepSkyBlue4Ter = 25, + DodgerBlue1 = 33, + DodgerBlue2 = 27, + DodgerBlue3 = 26, + Gold1 = 220, + Gold3 = 142, + Gold3Bis = 178, + Green1 = 46, + Green3 = 34, + Green3Bis = 40, + Green4 = 28, + GreenYellow = 154, + Grey0 = 16, + Grey100 = 231, + Grey11 = 234, + Grey15 = 235, + Grey19 = 236, + Grey23 = 237, + Grey27 = 238, + Grey3 = 232, + Grey30 = 239, + Grey35 = 240, + Grey37 = 59, + Grey39 = 241, + Grey42 = 242, + Grey46 = 243, + Grey50 = 244, + Grey53 = 102, + Grey54 = 245, + Grey58 = 246, + Grey62 = 247, + Grey63 = 139, + Grey66 = 248, + Grey69 = 145, + Grey7 = 233, + Grey70 = 249, + Grey74 = 250, + Grey78 = 251, + Grey82 = 252, + Grey84 = 188, + Grey85 = 253, + Grey89 = 254, + Grey93 = 255, + Honeydew2 = 194, + HotPink = 205, + HotPink2 = 169, + HotPink3 = 132, + HotPink3Bis = 168, + HotPinkBis = 206, + IndianRed = 131, + IndianRed1 = 203, + IndianRed1Bis = 204, + IndianRedBis = 167, + Khaki1 = 228, + Khaki3 = 185, + LightCoral = 210, + LightCyan1Bis = 195, + LightCyan3 = 152, + LightGoldenrod1 = 227, + LightGoldenrod2 = 186, + LightGoldenrod2Bis = 221, + LightGoldenrod2Ter = 222, + LightGoldenrod3 = 179, + LightGreen = 119, + LightGreenBis = 120, + LightPink1 = 217, + LightPink3 = 174, + LightPink4 = 95, + LightSalmon1 = 216, + LightSalmon3 = 137, + LightSalmon3Bis = 173, + LightSeaGreen = 37, + LightSkyBlue1 = 153, + LightSkyBlue3 = 109, + LightSkyBlue3Bis = 110, + LightSlateBlue = 105, + LightSlateGrey = 103, + LightSteelBlue = 147, + LightSteelBlue1 = 189, + LightSteelBlue3 = 146, + LightYellow3 = 187, + Magenta1 = 201, + Magenta2 = 165, + Magenta2Bis = 200, + Magenta3 = 127, + Magenta3Bis = 163, + Magenta3Ter = 164, + MediumOrchid = 134, + MediumOrchid1 = 171, + MediumOrchid1Bis = 207, + MediumOrchid3 = 133, + MediumPurple = 104, + MediumPurple1 = 141, + MediumPurple2 = 135, + MediumPurple2Bis = 140, + MediumPurple3 = 97, + MediumPurple3Bis = 98, + MediumPurple4 = 60, + MediumSpringGreen = 49, + MediumTurquoise = 80, + MediumVioletRed = 126, + MistyRose1 = 224, + MistyRose3 = 181, + NavajoWhite1 = 223, + NavajoWhite3 = 144, + NavyBlue = 17, + Orange1 = 214, + Orange3 = 172, + Orange4 = 58, + Orange4Bis = 94, + OrangeRed1 = 202, + Orchid = 170, + Orchid1 = 213, + Orchid2 = 212, + PaleGreen1 = 121, + PaleGreen1Bis = 156, + PaleGreen3 = 114, + PaleGreen3Bis = 77, + PaleTurquoise1 = 159, + PaleTurquoise4 = 66, + PaleVioletRed1 = 211, + Pink1 = 218, + Pink3 = 175, + Plum1 = 219, + Plum2 = 183, + Plum3 = 176, + Plum4 = 96, + Purple = 129, + Purple3 = 56, + Purple4 = 54, + Purple4Bis = 55, + PurpleBis = 93, + Red1 = 196, + Red3 = 124, + Red3Bis = 160, + RosyBrown = 138, + RoyalBlue1 = 63, + Salmon1 = 209, + SandyBrown = 215, + SeaGreen1 = 84, + SeaGreen1Bis = 85, + SeaGreen2 = 83, + SeaGreen3 = 78, + SkyBlue1 = 117, + SkyBlue2 = 111, + SkyBlue3 = 74, + SlateBlue1 = 99, + SlateBlue3 = 61, + SlateBlue3Bis = 62, + SpringGreen1 = 48, + SpringGreen2 = 42, + SpringGreen2Bis = 47, + SpringGreen3 = 35, + SpringGreen3Bis = 41, + SpringGreen4 = 29, + SteelBlue = 67, + SteelBlue1 = 75, + SteelBlue1Bis = 81, + SteelBlue3 = 68, + Tan = 180, + Thistle1 = 225, + Thistle3 = 182, + Turquoise2 = 45, + Turquoise4 = 30, + Violet = 177, + Wheat1 = 229, + Wheat4 = 101, + Yellow1 = 226, + Yellow2 = 190, + Yellow3 = 148, + Yellow3Bis = 184, + Yellow4 = 100, + Yellow4Bis = 106, + }; + // clang-format on + + // --- Operators ------ + bool operator==(const Color& rhs) const; + bool operator!=(const Color& rhs) const; + + std::string Print(bool is_background_color) const; + + private: + enum class ColorType : uint8_t { + Palette1, + Palette16, + Palette256, + TrueColor, + }; + ColorType type_ = ColorType::Palette1; + uint8_t red_ = 0; + uint8_t green_ = 0; + uint8_t blue_ = 0; +}; + +inline namespace literals { + +/// @brief Creates a color from a combined hex RGB representation, +/// e.g. 0x808000_rgb +Color operator""_rgb(unsigned long long int combined); + +} // namespace literals + +} // namespace ftxui + +#endif // FTXUI_SCREEN_COLOR_HPP diff --git a/include/ftxui/screen/color_info.hpp b/include/ftxui/screen/color_info.hpp new file mode 100644 index 0000000..8e625e8 --- /dev/null +++ b/include/ftxui/screen/color_info.hpp @@ -0,0 +1,29 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_COLOR_INFO_HPP +#define FTXUI_SCREEN_COLOR_INFO_HPP + +#include +#include + +namespace ftxui { + +struct ColorInfo { + const char* name; + uint8_t index_256; + uint8_t index_16; + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t hue; + uint8_t saturation; + uint8_t value; +}; + +ColorInfo GetColorInfo(Color::Palette256 index); +ColorInfo GetColorInfo(Color::Palette16 index); + +} // namespace ftxui + +#endif // FTXUI_SCREEN_COLOR_INFO_HPP diff --git a/include/ftxui/screen/deprecated.hpp b/include/ftxui/screen/deprecated.hpp new file mode 100644 index 0000000..e3a51f8 --- /dev/null +++ b/include/ftxui/screen/deprecated.hpp @@ -0,0 +1,14 @@ +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_DEPRECATED_HPP +#define FTXUI_SCREEN_DEPRECATED_HPP + +#include + +namespace ftxui { +int wchar_width(wchar_t); +int wstring_width(const std::wstring&); +} // namespace ftxui + +#endif // FTXUI_SCREEN_DEPRECATED_HPP diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp new file mode 100644 index 0000000..8d27900 --- /dev/null +++ b/include/ftxui/screen/screen.hpp @@ -0,0 +1,130 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_SCREEN_HPP +#define FTXUI_SCREEN_SCREEN_HPP + +#include // for uint8_t +#include +#include // for string, basic_string, allocator +#include // for vector + +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/color.hpp" // for Color, Color::Default +#include "ftxui/screen/terminal.hpp" // for Dimensions + +namespace ftxui { + +/// @brief A unicode character and its associated style. +/// @ingroup screen +struct Pixel { + Pixel() + : blink(false), + bold(false), + dim(false), + inverted(false), + underlined(false), + underlined_double(false), + strikethrough(false), + automerge(false) {} + + // A bit field representing the style: + bool blink : 1; + bool bold : 1; + bool dim : 1; + bool inverted : 1; + bool underlined : 1; + bool underlined_double : 1; + bool strikethrough : 1; + bool automerge : 1; + + // The hyperlink associated with the pixel. + // 0 is the default value, meaning no hyperlink. + uint8_t hyperlink = 0; + + // The graphemes stored into the pixel. To support combining characters, + // like: a⃦, this can potentially contain multiple codepoints. + std::string character = " "; + + // Colors: + Color background_color = Color::Default; + Color foreground_color = Color::Default; +}; + +/// @brief Define how the Screen's dimensions should look like. +/// @ingroup screen +namespace Dimension { +Dimensions Fixed(int); +Dimensions Full(); +} // namespace Dimension + +/// @brief A rectangular grid of Pixel. +/// @ingroup screen +class Screen { + public: + // Constructors: + Screen(int dimx, int dimy); + static Screen Create(Dimensions dimension); + static Screen Create(Dimensions width, Dimensions height); + + // Access a character in the grid at a given position. + std::string& at(int x, int y); + const std::string& at(int x, int y) const; + + // Access a cell (Pixel) in the grid at a given position. + Pixel& PixelAt(int x, int y); + const Pixel& PixelAt(int x, int y) const; + + std::string ToString() const; + + // Print the Screen on to the terminal. + void Print() const; + + // Get screen dimensions. + int dimx() const { return dimx_; } + int dimy() const { return dimy_; } + + // Move the terminal cursor n-lines up with n = dimy(). + std::string ResetPosition(bool clear = false) const; + + // Fill the screen with space. + void Clear(); + + void ApplyShader(); + + struct Cursor { + int x = 0; + int y = 0; + + enum Shape { + Hidden = 0, + BlockBlinking = 1, + Block = 2, + UnderlineBlinking = 3, + Underline = 4, + BarBlinking = 5, + Bar = 6, + }; + Shape shape; + }; + Cursor cursor() const { return cursor_; } + void SetCursor(Cursor cursor) { cursor_ = cursor; } + + // Store an hyperlink in the screen. Return the id of the hyperlink. The id is + // used to identify the hyperlink when the user click on it. + uint8_t RegisterHyperlink(const std::string& link); + const std::string& Hyperlink(uint8_t id) const; + + Box stencil; + + protected: + int dimx_; + int dimy_; + std::vector> pixels_; + Cursor cursor_; + std::vector hyperlinks_ = {""}; +}; + +} // namespace ftxui + +#endif // FTXUI_SCREEN_SCREEN_HPP diff --git a/include/ftxui/screen/string.hpp b/include/ftxui/screen/string.hpp new file mode 100644 index 0000000..70e761c --- /dev/null +++ b/include/ftxui/screen/string.hpp @@ -0,0 +1,35 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_STRING_HPP +#define FTXUI_SCREEN_STRING_HPP + +#include // for size_t +#include // for uint8_t +#include // for string, wstring, to_string +#include // for vector + +namespace ftxui { +std::string to_string(const std::wstring& s); +std::wstring to_wstring(const std::string& s); + +template +std::wstring to_wstring(T s) { + return to_wstring(std::to_string(s)); +} + +int string_width(const std::string&); + +// Split the string into a its glyphs. An empty one is inserted ater fullwidth +// ones. +std::vector Utf8ToGlyphs(const std::string& input); + +// Map every cells drawn by |input| to their corresponding Glyphs. Half-size +// Glyphs takes one cell, full-size Glyphs take two cells. +std::vector CellToGlyphIndex(const std::string& input); + +} // namespace ftxui + +#include "ftxui/screen/deprecated.hpp" + +#endif /* end of include guard: FTXUI_SCREEN_STRING_HPP */ diff --git a/include/ftxui/screen/terminal.hpp b/include/ftxui/screen/terminal.hpp new file mode 100644 index 0000000..051aed0 --- /dev/null +++ b/include/ftxui/screen/terminal.hpp @@ -0,0 +1,30 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_SCREEN_TERMINAL_HPP +#define FTXUI_SCREEN_TERMINAL_HPP + +namespace ftxui { +struct Dimensions { + int dimx; + int dimy; +}; + +namespace Terminal { +Dimensions Size(); +void SetFallbackSize(const Dimensions& fallbackSize); + +enum Color { + Palette1, + Palette16, + Palette256, + TrueColor, +}; +Color ColorSupport(); +void SetColorSupport(Color color); + +} // namespace Terminal + +} // namespace ftxui + +#endif // FTXUI_SCREEN_TERMINAL_HPP diff --git a/include/ftxui/util/autoreset.hpp b/include/ftxui/util/autoreset.hpp new file mode 100644 index 0000000..2c8bf4e --- /dev/null +++ b/include/ftxui/util/autoreset.hpp @@ -0,0 +1,28 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_UTIL_AUTORESET_HPP +#define FTXUI_UTIL_AUTORESET_HPP + +#include + +namespace ftxui { + +/// Assign a value to a variable, reset its old value when going out of scope. +template +class AutoReset { + public: + AutoReset(T* variable, T new_value) + : variable_(variable), previous_value_(std::move(*variable)) { + *variable_ = std::move(new_value); + } + ~AutoReset() { *variable_ = std::move(previous_value_); } + + private: + T* variable_; + T previous_value_; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_UTIL_AUTORESET_HPP */ diff --git a/include/ftxui/util/ref.hpp b/include/ftxui/util/ref.hpp new file mode 100644 index 0000000..1128b91 --- /dev/null +++ b/include/ftxui/util/ref.hpp @@ -0,0 +1,133 @@ +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. +#ifndef FTXUI_UTIL_REF_HPP +#define FTXUI_UTIL_REF_HPP + +#include +#include +#include + +namespace ftxui { + +/// @brief An adapter. Own or reference an immutable object. +template +class ConstRef { + public: + ConstRef() = default; + ConstRef(const ConstRef&) = default; + ConstRef(ConstRef&&) = default; + ConstRef(T t) : variant_(std::move(t)) {} + ConstRef(const T* t) : variant_(t) {} + + // Make a "reseatable" reference + ConstRef& operator=(const ConstRef&) = default; + + // Accessors: + const T& operator()() const { return *Address(); } + const T& operator*() const { return *Address(); } + const T* operator->() const { return Address(); } + + private: + std::variant variant_ = T{}; + + const T* Address() const { + return std::holds_alternative(variant_) ? &std::get(variant_) + : std::get(variant_); + } +}; + +/// @brief An adapter. Own or reference an mutable object. +template +class Ref { + public: + Ref() = default; + Ref(const Ref&) = default; + Ref(Ref&&) = default; + Ref(T t) : variant_(std::move(t)) {} + Ref(T* t) : variant_(t) {} + + // Make a "reseatable" reference. + Ref& operator=(const Ref&) = default; + + // Accessors: + T& operator()() { return *Address(); } + T& operator*() { return *Address(); } + T* operator->() { return Address(); } + const T& operator()() const { return *Address(); } + const T& operator*() const { return *Address(); } + const T* operator->() const { return Address(); } + + private: + std::variant variant_ = T{}; + + const T* Address() const { + return std::holds_alternative(variant_) ? &std::get(variant_) + : std::get(variant_); + } + T* Address() { + return std::holds_alternative(variant_) ? &std::get(variant_) + : std::get(variant_); + } +}; + +/// @brief An adapter. Own or reference a constant string. For convenience, this +/// class convert multiple mutable string toward a shared representation. +class StringRef : public Ref { + public: + using Ref::Ref; + + StringRef(const wchar_t* ref) : StringRef(to_string(std::wstring(ref))) {} + StringRef(const char* ref) : StringRef(std::string(ref)) {} +}; + +/// @brief An adapter. Own or reference a constant string. For convenience, this +/// class convert multiple immutable string toward a shared representation. +class ConstStringRef : public ConstRef { + public: + using ConstRef::ConstRef; + + ConstStringRef(const std::wstring* ref) : ConstStringRef(to_string(*ref)) {} + ConstStringRef(const std::wstring ref) : ConstStringRef(to_string(ref)) {} + ConstStringRef(const wchar_t* ref) + : ConstStringRef(to_string(std::wstring(ref))) {} + ConstStringRef(const char* ref) : ConstStringRef(std::string(ref)) {} +}; + +/// @brief An adapter. Reference a list of strings. +class ConstStringListRef { + public: + ConstStringListRef() = default; + ConstStringListRef(const std::vector* ref) : ref_(ref) {} + ConstStringListRef(const std::vector* ref) : ref_wide_(ref) {} + ConstStringListRef(const ConstStringListRef& other) = default; + ConstStringListRef& operator=(const ConstStringListRef& other) = default; + + size_t size() const { + if (ref_) { + return ref_->size(); + } + if (ref_wide_) { + return ref_wide_->size(); + } + return 0; + } + + std::string operator[](size_t i) const { + if (ref_) { + return (*ref_)[i]; + } + if (ref_wide_) { + return to_string((*ref_wide_)[i]); + } + return ""; + } + + private: + const std::vector* ref_ = nullptr; + const std::vector* ref_wide_ = nullptr; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_UTIL_REF_HPP */ diff --git a/lib/ftxui/libftxui-component.a b/lib/ftxui/libftxui-component.a new file mode 100644 index 0000000..80101f9 Binary files /dev/null and b/lib/ftxui/libftxui-component.a differ diff --git a/lib/ftxui/libftxui-dom.a b/lib/ftxui/libftxui-dom.a new file mode 100644 index 0000000..73f865a Binary files /dev/null and b/lib/ftxui/libftxui-dom.a differ diff --git a/lib/ftxui/libftxui-screen.a b/lib/ftxui/libftxui-screen.a new file mode 100644 index 0000000..a57981a Binary files /dev/null and b/lib/ftxui/libftxui-screen.a differ diff --git a/src/connect.cpp b/src/connect.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/connect.hpp b/src/connect.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c3c88b4 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,4 @@ + +int main() { + +}; diff --git a/src/parts.cpp b/src/parts.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/signals.cpp b/src/signals.cpp new file mode 100644 index 0000000..83f8842 --- /dev/null +++ b/src/signals.cpp @@ -0,0 +1,11 @@ + +#include "signals.hpp" + +Signal::Signal(std::string name) : SystemElement(name) { + +}; + +Signals::Signals(std::vector signals): SystemElementContainer("signals") { + add(signals); +} + diff --git a/src/signals.hpp b/src/signals.hpp new file mode 100644 index 0000000..365e3d1 --- /dev/null +++ b/src/signals.hpp @@ -0,0 +1,9 @@ +#include "syselmts.hpp" + +class Signal: public SystemElement { + Signal(std::string name); +}; + +class Signals: public SystemElementContainer { + Signals(std::vector signals); +}; \ No newline at end of file diff --git a/src/syselmts.hpp b/src/syselmts.hpp new file mode 100644 index 0000000..8226f80 --- /dev/null +++ b/src/syselmts.hpp @@ -0,0 +1,55 @@ + +#ifndef _SYSELEMENTS_HPP_ +#define _SYSELEMENTS_HPP_ + +#include +#include +#include +#include + +class SystemElement +{ +public: + std::string name; + SystemElement(std::string name): name(name) {}; +}; + +template +class SystemElementContainer : public SystemElement +{ +private: + static_assert(std::is_base_of::value, "T shall be a system element descendant !"); + unsigned int iter_count; + std::unordered_map content; + + bool name_exists(std::string name) { + return get(name) != nullptr; + } + +public: + SystemElementContainer(std::string name) : SystemElement(name) {}; + void add(const T element) { + if ("" == element.name) { + throw std::runtime_error("Elements with empty names are forbidden"); + } + if name_exists(element.name) { + throw std::runtime_error("Elements of same names are forbidden"); + } + content[element.name] = element; + } + void add(const std::vector elements) { + for (const auto& element: elements) { + + } + } + T* get(std::string name) { + auto it = content.find(name); + if (it != content.end()) { + return &it->second; + } else { + return nullptr; + } + } +}; + +#endif \ No newline at end of file diff --git a/src/system.cpp b/src/system.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/system.hpp b/src/system.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/transform.cpp b/src/transform.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/transform.hpp b/src/transform.hpp new file mode 100644 index 0000000..e69de29