diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ab5c744 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,86 @@ +# essim — notes for Claude + +System digital twin: simulator for the interconnections between cards/boards. C++17, FTXUI for the TUI, importers for external netlist formats. + +## Build + +```sh +cmake -S . -B build +cmake --build build -j +./build/essim +``` + +- CMake **3.14+** required (uses `FetchContent_MakeAvailable`). +- FTXUI is fetched at configure time from GitHub (`v6.1.9`, shallow clone). First configure pays ~20 s for the clone; subsequent ones are cached in `build/_deps/`. +- Sources are collected with `file(GLOB_RECURSE ALL_SOURCES "src/*.cpp")`. **After adding a new `.cpp`, re-run `cmake -S . -B build`** — CMake does not re-glob automatically and link will fail with "undefined reference". + +## Layout + +``` +src/ + main.cpp -- launches Tui + system/ -- domain model + syselmts.hpp SystemElement + SystemElementContainer (templated, get/merge/iterate) + modules.{hpp,cpp} Module, Modules + parts.{hpp,cpp} Part, Parts + pins.{hpp,cpp} Pin, Pins + signals.{hpp,cpp} Signal, Signals + connect.{hpp,cpp} Connection, Connections + transform.{hpp,cpp} transforms applied to the model + system.{hpp,cpp} System: owns Modules + Connections, exposes Load() + imports/ -- adapters that populate the domain + import_base.hpp ImportBase interface + import_mentor.{hpp,cpp} Mentor Graphics netlist parser (done) + tui/ -- FTXUI shell + tui.{hpp,cpp} Tui: visualisation area on top, input + history at the bottom +doc/classes.puml -- PlantUML class diagram +``` + +`include/` and `lib/` are kept empty by design — FTXUI used to live there as precompiled `.a` + headers, now it comes through FetchContent. + +## Domain conventions + +- Everything in `system/` is **pointer-based** (commit `d8122d1`: "everything is pointer"). Containers store `T*`, ownership lives with the container. +- `SystemElementContainer::merge(name)` is the get-or-create primitive — call it instead of `add` when you don't know whether the element already exists. `add` throws on duplicate names or empty names. +- `using namespace std;` is present in `syselmts.hpp` — pre-existing, don't add more `using namespace` in headers. +- Include guards `_NAME_HPP_` *and* `#pragma once` are both used. Match the existing style. + +## TUI + +`Tui::Run()` enters an FTXUI fullscreen loop: + +- Top: scrollable visualisation area (`window` + `vscroll_indicator | yframe`, last line gets `focus` so it auto-scrolls). +- Bottom: single-line `Input` inside a border. Label switches between `> ` (normal) and `? ` (during a multi-step prompt). +- `CatchEvent` is wrapped **outside** the `Renderer` (not between `Renderer` and `Input`). Pattern: `Renderer(input_component, lambda)` then `CatchEvent(renderer, handler)`. Wrapping `CatchEvent(input, …)` inside a `Container::Vertical({…})` and then `Renderer(container, …)` was found to break the `Input`'s content rendering on at least one terminal — typed characters didn't show even though `on_enter` fired correctly. +- `InputOption::transform` is overridden to avoid hard-coded colors (default sets `White on Black` when focused, which is unreadable on light terminal themes). The custom transform only applies `dim` to the placeholder; everything else inherits terminal default fg/bg, so the UI adapts to any theme. +- `InputOption::multiline` **must** be set to `false` for the command prompt. Default is `true`, and FTXUI's `HandleReturn()` then both inserts `\n` into the content **and** fires `on_enter` — so `Submit()` would receive `"help\n"` instead of `"help"` and command lookups would all fall through to "unknown command". +- Commands live in a `std::map` registry built in `RegisterCommands()`. Each `CommandSpec` declares a list of `Param{name, path_completion}` and an `action(args)` lambda. `Dispatch(raw)` tokenises the input (whitespace split with `"…"` quoting), takes inline args first, and pushes a `Prompt` onto the queue for each missing param. The last prompt's callback calls `Finalize()`. +- `Finalize()` rebuilds the **canonical inline form** (`name arg1 "arg with spaces" arg3`) and writes that to history — so a `load` command answered via interactive prompts still shows up in `history` (and on disk) as a single inline line, ready to be replayed via ↑. +- Multi-step prompts work via a `std::deque` queue. `Submit()` pops them one by one before falling back to dispatch. Adding a new command = one entry in `RegisterCommands()`; the prompt-flow and inline-flow are both handled automatically. +- Tab completion: at the top-level prompt (no `pending`), completes built-in command names. Inside a prompt with `path_completion = true` (e.g. the `filename` step of `load`), completes file paths via `std::filesystem::directory_iterator` (handles `~/`, dirs get a trailing `/`). Logic: 1 match → replace; multiple with progress on the longest common prefix → extend; multiple stuck at LCP → list candidates in the visualisation area. + +Built-in commands: `new`, `load`, `search`, `clear`, `help`, `quit`/`exit`. `Esc` cancels an in-progress multi-step prompt. + +`search` switches to a second full-screen layout (handled by `Container::Tab({main, search}, &screen_idx)`). Layout: +- Left column: `Menu` for the module list and `Menu` for the type (`parts` / `signals`). +- Right column: `Input` for the live filter query, plus a results panel rebuilt every frame. +- `Tab` cycles focus between the query input and the menus. **Implemented manually** in the outer `CatchEvent`: `Menu::OnEvent` consumes `Event::Tab` to cycle its own entries and returns `true`, which prevents `Container::Vertical` from ever seeing the event (Container only cycles between children when the active child returns `false`). So we short-circuit Tab/TabReverse upstream and mutate `search_focus_idx` directly. +- `Esc` exits the search mode (flips `screen_idx` back to 0). The search state (selected module/type, query) is preserved across re-entries until `search` is run again. + +Adding a new screen mode = add a child to `Container::Tab` and a `screen_idx` value; key handling already lives in the outer `CatchEvent`. + +Command history is persisted on disk and loaded on startup. Path resolution is platform-aware: +- Linux/macOS: `$XDG_DATA_HOME/essim/history`, falling back to `~/.local/share/essim/history`. +- Windows: `%LOCALAPPDATA%\essim\history`, falling back to `%APPDATA%\…` then `%USERPROFILE%\AppData\Local\…`. + +Each successful submission appends a single line to the file (so a crash doesn't lose history). Multi-step prompt answers are NOT persisted — only top-level commands. + +## Gotchas + +- `System::Load` for `IMPORT_ALTIUM` / `IMPORT_ODS`: the corresponding constructor lines are commented out, so `imp` stays uninitialised → UB on `imp->parse(...)`. Only `IMPORT_MENTOR` is safe today. Wrap calls in `try/catch` (the TUI does). +- `System::Load` throws `std::runtime_error("Unknown import type")` for any value outside the three enum cases. +- `Modules`/`Parts`/etc. have no const-correct iteration on the `*` accessor; iterators on `SystemElementContainer` are available but `begin()`/`end()` are non-const-safe in some places. + +## Memory layout for sessions + +Persistent notes live in `~/.claude/projects/-home-francois-Projets-essim/memory/`. Index: `MEMORY.md`. Add project/feedback/user/reference entries there when relevant — see top-level Claude Code memory rules. diff --git a/CMakeLists.txt b/CMakeLists.txt index 67fcdc5..a0a4819 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.12) +cmake_minimum_required(VERSION 3.14) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -9,20 +9,29 @@ project(essim DESCRIPTION "System digital twin." ) -set(DIR_LIBS ${CMAKE_SOURCE_DIR}/libs) +include(FetchContent) + +set(FTXUI_BUILD_DOCS OFF CACHE INTERNAL "") +set(FTXUI_BUILD_EXAMPLES OFF CACHE INTERNAL "") +set(FTXUI_BUILD_TESTS OFF CACHE INTERNAL "") +set(FTXUI_ENABLE_INSTALL OFF CACHE INTERNAL "") + +FetchContent_Declare(ftxui + GIT_REPOSITORY https://github.com/ArthurSonzogni/FTXUI.git + GIT_TAG v6.1.9 + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(ftxui) + file(GLOB_RECURSE ALL_SOURCES "src/*.cpp") -file(GLOB_RECURSE LIB_FTXUI "lib/ftxui/*.a") +add_executable(essim ${ALL_SOURCES}) +target_include_directories(essim PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -add_executable( - essim - ${ALL_SOURCES} +target_link_libraries(essim + PRIVATE + ftxui::screen + ftxui::dom + ftxui::component ) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) - -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 deleted file mode 100644 index c9f665e..0000000 --- a/include/ftxui/component/animation.hpp +++ /dev/null @@ -1,118 +0,0 @@ -// 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 deleted file mode 100644 index 4ed6d75..0000000 --- a/include/ftxui/component/captured_mouse.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// 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 deleted file mode 100644 index 9847603..0000000 --- a/include/ftxui/component/component.hpp +++ /dev/null @@ -1,142 +0,0 @@ -// 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 deleted file mode 100644 index 1e3fa13..0000000 --- a/include/ftxui/component/component_base.hpp +++ /dev/null @@ -1,98 +0,0 @@ -// 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 deleted file mode 100644 index b401b6d..0000000 --- a/include/ftxui/component/component_options.hpp +++ /dev/null @@ -1,267 +0,0 @@ -// 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 deleted file mode 100644 index 504bee0..0000000 --- a/include/ftxui/component/event.hpp +++ /dev/null @@ -1,112 +0,0 @@ -// 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 deleted file mode 100644 index 41b340c..0000000 --- a/include/ftxui/component/loop.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// 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 deleted file mode 100644 index 3c61008..0000000 --- a/include/ftxui/component/mouse.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// 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 deleted file mode 100644 index 95f2353..0000000 --- a/include/ftxui/component/receiver.hpp +++ /dev/null @@ -1,140 +0,0 @@ -// 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 deleted file mode 100644 index 10d022c..0000000 --- a/include/ftxui/component/screen_interactive.hpp +++ /dev/null @@ -1,127 +0,0 @@ -// 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 deleted file mode 100644 index 6a770e8..0000000 --- a/include/ftxui/component/task.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// 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 deleted file mode 100644 index 9286838..0000000 --- a/include/ftxui/dom/canvas.hpp +++ /dev/null @@ -1,138 +0,0 @@ -// 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 deleted file mode 100644 index f4faf8d..0000000 --- a/include/ftxui/dom/deprecated.hpp +++ /dev/null @@ -1,15 +0,0 @@ -// 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 deleted file mode 100644 index 2a38f09..0000000 --- a/include/ftxui/dom/direction.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// 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 deleted file mode 100644 index ffd9360..0000000 --- a/include/ftxui/dom/elements.hpp +++ /dev/null @@ -1,196 +0,0 @@ -// 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 deleted file mode 100644 index 8ae2677..0000000 --- a/include/ftxui/dom/flexbox_config.hpp +++ /dev/null @@ -1,114 +0,0 @@ -// 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 deleted file mode 100644 index da7e77b..0000000 --- a/include/ftxui/dom/linear_gradient.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// 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 deleted file mode 100644 index a462b0a..0000000 --- a/include/ftxui/dom/node.hpp +++ /dev/null @@ -1,66 +0,0 @@ -// 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 deleted file mode 100644 index 1b0a884..0000000 --- a/include/ftxui/dom/requirement.hpp +++ /dev/null @@ -1,34 +0,0 @@ -// 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 deleted file mode 100644 index 5b7fd34..0000000 --- a/include/ftxui/dom/table.hpp +++ /dev/null @@ -1,95 +0,0 @@ -// 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 deleted file mode 100644 index 79491ef..0000000 --- a/include/ftxui/dom/take_any_args.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// 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 deleted file mode 100644 index 701b600..0000000 --- a/include/ftxui/screen/box.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// 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 deleted file mode 100644 index 8939e50..0000000 --- a/include/ftxui/screen/color.hpp +++ /dev/null @@ -1,336 +0,0 @@ -// 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 deleted file mode 100644 index 8e625e8..0000000 --- a/include/ftxui/screen/color_info.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// 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 deleted file mode 100644 index e3a51f8..0000000 --- a/include/ftxui/screen/deprecated.hpp +++ /dev/null @@ -1,14 +0,0 @@ -// 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 deleted file mode 100644 index 8d27900..0000000 --- a/include/ftxui/screen/screen.hpp +++ /dev/null @@ -1,130 +0,0 @@ -// 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 deleted file mode 100644 index 70e761c..0000000 --- a/include/ftxui/screen/string.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// 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 deleted file mode 100644 index 051aed0..0000000 --- a/include/ftxui/screen/terminal.hpp +++ /dev/null @@ -1,30 +0,0 @@ -// 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 deleted file mode 100644 index 2c8bf4e..0000000 --- a/include/ftxui/util/autoreset.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// 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 deleted file mode 100644 index 1128b91..0000000 --- a/include/ftxui/util/ref.hpp +++ /dev/null @@ -1,133 +0,0 @@ -// 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 deleted file mode 100644 index 80101f9..0000000 Binary files a/lib/ftxui/libftxui-component.a and /dev/null differ diff --git a/lib/ftxui/libftxui-dom.a b/lib/ftxui/libftxui-dom.a deleted file mode 100644 index 73f865a..0000000 Binary files a/lib/ftxui/libftxui-dom.a and /dev/null differ diff --git a/lib/ftxui/libftxui-screen.a b/lib/ftxui/libftxui-screen.a deleted file mode 100644 index a57981a..0000000 Binary files a/lib/ftxui/libftxui-screen.a and /dev/null differ diff --git a/src/main.cpp b/src/main.cpp index ba7d9c3..3db67c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,7 @@ -#include "system/system.hpp" - -using namespace std; +#include "tui/tui.hpp" int main() { - System *sys = new System(); - string ment_filename = "/home/francois/Projets/twinsys/test/BPB-2177_Netlist_2_3.qcv"; - - sys->Load("bpb", ment_filename, ImportType::IMPORT_MENTOR); - delete sys; -}; + Tui tui; + tui.Run(); + return 0; +} diff --git a/src/system/syselmts.hpp b/src/system/syselmts.hpp index cf3625f..8846eab 100644 --- a/src/system/syselmts.hpp +++ b/src/system/syselmts.hpp @@ -175,6 +175,8 @@ public: } } + size_t size() const { return content.size(); } + /** * @brief Returns an iterator to the beginning of the container. * @return Iterator to the beginning. diff --git a/src/system/system.hpp b/src/system/system.hpp index ea4e965..6846893 100644 --- a/src/system/system.hpp +++ b/src/system/system.hpp @@ -22,6 +22,7 @@ class System public: System(); void Load(std::string module_name, std::string filename, ImportType type); + Modules *modules() const { return mods; } ~System(); }; diff --git a/src/tui/tui.cpp b/src/tui/tui.cpp new file mode 100644 index 0000000..9fde186 --- /dev/null +++ b/src/tui/tui.cpp @@ -0,0 +1,482 @@ +#include "tui/tui.hpp" + +#include "system/modules.hpp" +#include "system/parts.hpp" +#include "system/signals.hpp" +#include "system/system.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ftxui; + +Tui::Tui() + : cursor_pos(0), history_idx(-1), quit(false), + screen_idx(0), + search_types{"parts", "signals"}, + search_module_idx(0), search_type_idx(0), search_focus_idx(0) +{ + LoadHistory(); + RegisterCommands(); + Print("essim — type 'help' for commands, 'quit' to exit."); +} + +Tui::~Tui() = default; + +void Tui::Print(const std::string &line) { + output.push_back(line); +} + +void Tui::HistoryUp() { + if (history.empty()) return; + if (history_idx == -1) history_idx = (int)history.size() - 1; + else if (history_idx > 0) history_idx--; + input = history[history_idx]; + cursor_pos = (int)input.size(); +} + +void Tui::HistoryDown() { + if (history_idx == -1) return; + history_idx++; + if (history_idx >= (int)history.size()) { + history_idx = -1; + input.clear(); + } else { + input = history[history_idx]; + } + cursor_pos = (int)input.size(); +} + +void Tui::CancelPending() { + if (pending.empty()) return; + pending.clear(); + input.clear(); + cursor_pos = 0; + history_idx = -1; + Print("(cancelled)"); +} + +static std::string ToLower(std::string s) { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return std::tolower(c); }); + return s; +} + +std::vector Tui::Tokenize(const std::string &s) { + std::vector out; + std::string cur; + bool in_q = false; + for (char c : s) { + if (c == '"') { in_q = !in_q; continue; } + if (!in_q && std::isspace((unsigned char)c)) { + if (!cur.empty()) { out.push_back(std::move(cur)); cur.clear(); } + } else { + cur.push_back(c); + } + } + if (!cur.empty()) out.push_back(std::move(cur)); + return out; +} + +void Tui::RegisterCommands() { + commands["help"] = { {}, [this](auto &) { + Print("Commands (give params inline or fill them in via prompt):"); + Print(" new create a new (empty) system"); + Print(" load load a module into the system"); + Print(" search interactive search (parts/signals, live filter)"); + Print(" clear clear the visualization area"); + Print(" help show this message"); + Print(" quit / exit leave essim"); + Print(" Esc cancel a multi-step prompt"); + Print(" Tab complete command name / file path"); + }}; + commands["clear"] = { {}, [this](auto &) { output.clear(); }}; + commands["quit"] = { {}, [this](auto &) { quit = true; }}; + commands["exit"] = { {}, [this](auto &) { quit = true; }}; + commands["new"] = { {}, [this](auto &) { + sys = std::make_unique(); + Print("system created."); + }}; + commands["load"] = { + {{"module name", false}, + {"filename", true}, + {"import type [mentor|altium|ods]", false}}, + [this](const std::vector &args) { + if (!sys) { Print("no system: run 'new' first."); return; } + std::string ls = args[2]; + std::transform(ls.begin(), ls.end(), ls.begin(), + [](unsigned char c) { return std::tolower(c); }); + ImportType t; + if (ls == "mentor") t = ImportType::IMPORT_MENTOR; + else if (ls == "altium") t = ImportType::IMPORT_ALTIUM; + else if (ls == "ods") t = ImportType::IMPORT_ODS; + else { Print("unknown import type: " + args[2]); return; } + try { + sys->Load(args[0], args[1], t); + Module *mod = sys->modules()->get(args[0]); + Print("loaded '" + args[0] + "' from " + args[1]); + Print(" parts: " + std::to_string(mod->size())); + Print(" signals: " + std::to_string(mod->signals->size())); + } catch (const std::exception &e) { + Print(std::string("load failed: ") + e.what()); + } + } + }; + commands["search"] = { {}, [this](auto &) { + if (!sys) { Print("no system: run 'new' first."); return; } + search_modules.clear(); + for (auto &m : *sys->modules()) search_modules.push_back(m.first); + if (search_modules.empty()) { Print("no modules loaded."); return; } + search_module_idx = 0; + search_type_idx = 0; + search_query.clear(); + search_focus_idx = 0; // start with the query input focused + screen_idx = 1; + }}; +} + +void Tui::Submit() { + if (!pending.empty()) { + if (input.empty()) { Print("(empty — Esc to cancel)"); return; } + Prompt p = std::move(pending.front()); + pending.pop_front(); + Print(" " + p.question + ": " + input); + std::string answer = std::move(input); + input.clear(); + cursor_pos = 0; + history_idx = -1; + p.on_answer(answer); + return; + } + + if (input.empty()) return; + history_idx = -1; + Print("> " + input); + std::string raw = std::move(input); + input.clear(); + cursor_pos = 0; + Dispatch(raw); +} + +void Tui::Dispatch(const std::string &raw) { + auto tokens = Tokenize(raw); + if (tokens.empty()) return; + + auto it = commands.find(tokens[0]); + if (it == commands.end()) { + Print("unknown command: " + tokens[0]); + history.push_back(raw); + AppendHistory(raw); + return; + } + + const std::string name = it->first; + const CommandSpec &spec = it->second; + + if (tokens.size() - 1 > spec.params.size()) { + Print("too many arguments for '" + name + "'"); + history.push_back(raw); + AppendHistory(raw); + return; + } + + auto args = std::make_shared>( + tokens.begin() + 1, tokens.end()); + + if (args->size() == spec.params.size()) { + Finalize(name, spec, *args); + return; + } + + for (size_t i = args->size(); i < spec.params.size(); ++i) { + bool last = (i + 1 == spec.params.size()); + const auto ¶m = spec.params[i]; + pending.push_back({ + param.name, + [this, name, &spec, args, last](const std::string &s) { + args->push_back(s); + if (last) Finalize(name, spec, *args); + }, + param.path_completion, + }); + } +} + +void Tui::Finalize(const std::string &name, + const CommandSpec &spec, + const std::vector &args) { + std::string canonical = name; + for (const auto &a : args) { + if (a.find_first_of(" \t\"") != std::string::npos) + canonical += " \"" + a + "\""; + else + canonical += " " + a; + } + history.push_back(canonical); + AppendHistory(canonical); + spec.action(args); +} + +static std::filesystem::path HistoryPath() { + namespace fs = std::filesystem; +#ifdef _WIN32 + if (const char *p = std::getenv("LOCALAPPDATA"); p && *p) + return fs::path(p) / "essim" / "history"; + if (const char *p = std::getenv("APPDATA"); p && *p) + return fs::path(p) / "essim" / "history"; + if (const char *p = std::getenv("USERPROFILE"); p && *p) + return fs::path(p) / "AppData" / "Local" / "essim" / "history"; +#else + if (const char *p = std::getenv("XDG_DATA_HOME"); p && *p) + return fs::path(p) / "essim" / "history"; + if (const char *p = std::getenv("HOME"); p && *p) + return fs::path(p) / ".local" / "share" / "essim" / "history"; +#endif + return {}; +} + +void Tui::LoadHistory() { + auto p = HistoryPath(); + if (p.empty()) return; + std::ifstream f(p); + std::string line; + while (std::getline(f, line)) + if (!line.empty()) history.push_back(line); +} + +void Tui::AppendHistory(const std::string &cmd) { + auto p = HistoryPath(); + if (p.empty()) return; + std::string trimmed = cmd; + while (!trimmed.empty() && std::isspace((unsigned char)trimmed.back())) + trimmed.pop_back(); + if (trimmed.empty()) return; + std::error_code ec; + std::filesystem::create_directories(p.parent_path(), ec); + if (ec) return; + std::ofstream f(p, std::ios::app); + if (f) f << trimmed << '\n'; +} + +static std::string LongestCommonPrefix(const std::vector &v) { + if (v.empty()) return ""; + std::string lcp = v[0]; + for (size_t i = 1; i < v.size(); ++i) { + size_t k = 0; + while (k < lcp.size() && k < v[i].size() && lcp[k] == v[i][k]) ++k; + lcp.resize(k); + } + return lcp; +} + +void Tui::CompleteCommand() { + std::vector matches; + for (const auto &kv : commands) + if (kv.first.rfind(input, 0) == 0) matches.push_back(kv.first); + + if (matches.empty()) return; + if (matches.size() == 1) { input = matches[0]; cursor_pos = (int)input.size(); return; } + + std::string lcp = LongestCommonPrefix(matches); + if (lcp.size() > input.size()) { input = lcp; cursor_pos = (int)input.size(); return; } + + std::string line = " "; + for (const auto &m : matches) line += " " + m; + Print(line); +} + +void Tui::CompletePath() { + namespace fs = std::filesystem; + + auto pos = input.rfind('/'); + std::string disp, prefix; + if (pos == std::string::npos) { disp = ""; prefix = input; } + else { disp = input.substr(0, pos + 1); prefix = input.substr(pos + 1); } + + std::string resolved = disp.empty() ? "." : disp; + if (!resolved.empty() && resolved[0] == '~') { + if (const char *home = std::getenv("HOME")) + resolved = std::string(home) + resolved.substr(1); + } + + std::vector names; + std::vector is_dir; + try { + for (const auto &e : fs::directory_iterator(resolved)) { + std::string n = e.path().filename().string(); + if (n.rfind(prefix, 0) == 0) { + names.push_back(n); + is_dir.push_back(e.is_directory()); + } + } + } catch (const std::exception &) { + return; + } + if (names.empty()) return; + + if (names.size() == 1) { + input = disp + names[0] + (is_dir[0] ? "/" : ""); + cursor_pos = (int)input.size(); + return; + } + + std::string lcp = LongestCommonPrefix(names); + if (lcp.size() > prefix.size()) { input = disp + lcp; cursor_pos = (int)input.size(); return; } + + std::string line = " "; + for (size_t i = 0; i < names.size(); ++i) + line += " " + names[i] + (is_dir[i] ? "/" : ""); + Print(line); +} + +void Tui::Run() { + auto screen = ScreenInteractive::Fullscreen(); + + // ---- Main TUI ---- + InputOption opt; + opt.multiline = false; + opt.cursor_position = &cursor_pos; + opt.on_enter = [this] { Submit(); }; + opt.transform = [](InputState s) { + auto el = s.element; + if (s.is_placeholder) el |= dim; + return el; + }; + auto input_component = Input(&input, "type a command…", opt); + + auto main_renderer = Renderer(input_component, [this, &screen, input_component] { + if (quit) screen.Exit(); + + Elements lines; + for (const auto &l : output) lines.push_back(text(l)); + auto view = vbox(std::move(lines)) + | focusPositionRelative(0, 1) + | yframe + | flex; + + std::string label = pending.empty() + ? "> " + : pending.front().question + "? "; + + return vbox({ + view, + separator(), + hbox({text(label), input_component->Render()}), + }) | border; + }); + + // ---- Search screen ---- + InputOption query_opt; + query_opt.multiline = false; + query_opt.transform = opt.transform; + auto query_input = Input(&search_query, "filter…", query_opt); + auto module_menu = Menu(&search_modules, &search_module_idx); + auto type_menu = Menu(&search_types, &search_type_idx); + + auto search_components = Container::Vertical( + {query_input, module_menu, type_menu}, &search_focus_idx); + + auto search_renderer = Renderer(search_components, + [this, query_input, module_menu, type_menu] { + // Compute filtered list. + Elements result_lines; + int total = 0; + if (!search_modules.empty() && sys) { + const std::string &mname = search_modules[search_module_idx]; + try { + Module *mod = sys->modules()->get(mname); + std::string needle = ToLower(search_query); + if (search_type_idx == 0) { // parts + for (auto &pkv : *mod) { + if (needle.empty() + || ToLower(pkv.first).find(needle) != std::string::npos) { + result_lines.push_back( + text(" " + pkv.first + + " (" + std::to_string(pkv.second->size()) + " pins)")); + ++total; + } + } + } else { // signals + for (auto &skv : *mod->signals) { + if (needle.empty() + || ToLower(skv.first).find(needle) != std::string::npos) { + result_lines.push_back( + text(" " + skv.first + + " (" + std::to_string(skv.second->size()) + " pins)")); + ++total; + } + } + } + } catch (const std::exception &) {} + } + + auto left = vbox({ + text("module") | bold, + module_menu->Render() | yframe | flex, + separator(), + text("type") | bold, + type_menu->Render(), + }) | size(WIDTH, EQUAL, 28); + + auto right = vbox({ + hbox({text(" search: "), query_input->Render() | flex}) | border, + text(std::to_string(total) + " match(es)") | dim, + vbox(std::move(result_lines)) | yframe | flex, + }) | flex; + + return vbox({ + hbox({left, separator(), right}) | flex, + text(" Tab: cycle focus | Esc: leave search ") | dim, + }) | border; + }); + + // ---- Screen tab + global key handling ---- + auto tab = Container::Tab({main_renderer, search_renderer}, &screen_idx); + + auto root = CatchEvent(tab, [this](Event e) { + if (screen_idx == 1) { + // Search mode + if (e == Event::Escape) { screen_idx = 0; return true; } + // Cycle focus query → modules → type → query (Menu eats Tab otherwise). + if (e == Event::Tab) { + search_focus_idx = (search_focus_idx + 1) % 3; + return true; + } + if (e == Event::TabReverse) { + search_focus_idx = (search_focus_idx + 2) % 3; + return true; + } + return false; // let menus / input handle the rest + } + + // Main mode + if (e == Event::Escape && !pending.empty()) { CancelPending(); return true; } + if (e == Event::ArrowUp || e == Event::ArrowDown) { + if (pending.empty()) { + if (e == Event::ArrowUp) HistoryUp(); + else HistoryDown(); + } + return true; + } + if (e == Event::Tab) { + if (pending.empty()) { + if (input.find(' ') == std::string::npos) CompleteCommand(); + } else if (pending.front().path_completion) { + CompletePath(); + } + return true; + } + return false; + }); + + screen.Loop(root); +} diff --git a/src/tui/tui.hpp b/src/tui/tui.hpp new file mode 100644 index 0000000..0af9a33 --- /dev/null +++ b/src/tui/tui.hpp @@ -0,0 +1,75 @@ +#ifndef _TUI_HPP_ +#define _TUI_HPP_ + +#include +#include +#include +#include +#include +#include + +class System; + +class Tui { + struct Prompt { + std::string question; + std::function on_answer; + bool path_completion = false; + }; + + struct CommandSpec { + struct Param { + std::string name; + bool path_completion = false; + }; + std::vector params; + std::function &)> action; + }; + + std::vector history; + std::vector output; + std::string input; + int cursor_pos; + int history_idx; + bool quit; + + std::unique_ptr sys; + std::deque pending; + std::map commands; + + int screen_idx; + std::vector search_modules; + std::vector search_types; + int search_module_idx; + int search_type_idx; + int search_focus_idx; + std::string search_query; + +public: + Tui(); + ~Tui(); + void Run(); + +private: + void RegisterCommands(); + void Submit(); + void Dispatch(const std::string &raw); + void Finalize(const std::string &name, + const CommandSpec &spec, + const std::vector &args); + + void HistoryUp(); + void HistoryDown(); + void CancelPending(); + void Print(const std::string &line); + + void CompleteCommand(); + void CompletePath(); + + void LoadHistory(); + void AppendHistory(const std::string &cmd); + + static std::vector Tokenize(const std::string &s); +}; + +#endif // _TUI_HPP_