TUI shell + ftxui via FetchContent.
- ftxui v6.1.9 fetched at configure time; vendored .a + headers dropped. - TUI: visualisation area on top, input prompt at the bottom; ↑/↓ history, Tab completion (commands + file paths), Esc cancels prompts. History is persisted (XDG on Linux, %LOCALAPPDATA% on Windows when ported). - Command registry: `new`, `load`, `search`, `clear`, `help`, `quit`/`exit`. Inline params or interactive prompts; either way the canonical inline form is what gets stored in history. - `search`: second full-screen mode with module + parts/signals menus and a live-filtered list; Tab cycles focus, Esc returns to the main shell. - Domain: `System::modules()` accessor + `SystemElementContainer::size()` to support load summary + search. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
86
CLAUDE.md
Normal file
86
CLAUDE.md
Normal file
@@ -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<T> (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<T>::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 `<question>? ` (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<std::string, CommandSpec>` 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<Prompt>` 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<T>` 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.
|
||||
@@ -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}
|
||||
)
|
||||
@@ -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 <chrono> // for milliseconds, duration, steady_clock, time_point
|
||||
#include <functional> // for function
|
||||
|
||||
#include "ftxui/component/event.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
namespace animation {
|
||||
// Components who haven't completed their animation can call this function to
|
||||
// request a new frame to be drawn later.
|
||||
//
|
||||
// When there is no new events and no animations to complete, no new frame is
|
||||
// drawn.
|
||||
void RequestAnimationFrame();
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using TimePoint = std::chrono::time_point<Clock>;
|
||||
using Duration = std::chrono::duration<float>;
|
||||
|
||||
// Parameter of Component::OnAnimation(param).
|
||||
class Params {
|
||||
public:
|
||||
Params(Duration duration) : duration_(duration) {}
|
||||
|
||||
/// The duration this animation step represents.
|
||||
Duration duration() const { return duration_; }
|
||||
|
||||
private:
|
||||
Duration duration_;
|
||||
};
|
||||
|
||||
namespace easing {
|
||||
using Function = std::function<float(float)>;
|
||||
// Linear interpolation (no easing)
|
||||
float Linear(float p);
|
||||
|
||||
// Quadratic easing; p^2
|
||||
float QuadraticIn(float p);
|
||||
float QuadraticOut(float p);
|
||||
float QuadraticInOut(float p);
|
||||
|
||||
// Cubic easing; p^3
|
||||
float CubicIn(float p);
|
||||
float CubicOut(float p);
|
||||
float CubicInOut(float p);
|
||||
|
||||
// Quartic easing; p^4
|
||||
float QuarticIn(float p);
|
||||
float QuarticOut(float p);
|
||||
float QuarticInOut(float p);
|
||||
|
||||
// Quintic easing; p^5
|
||||
float QuinticIn(float p);
|
||||
float QuinticOut(float p);
|
||||
float QuinticInOut(float p);
|
||||
|
||||
// Sine wave easing; sin(p * PI/2)
|
||||
float SineIn(float p);
|
||||
float SineOut(float p);
|
||||
float SineInOut(float p);
|
||||
|
||||
// Circular easing; sqrt(1 - p^2)
|
||||
float CircularIn(float p);
|
||||
float CircularOut(float p);
|
||||
float CircularInOut(float p);
|
||||
|
||||
// Exponential easing, base 2
|
||||
float ExponentialIn(float p);
|
||||
float ExponentialOut(float p);
|
||||
float ExponentialInOut(float p);
|
||||
|
||||
// Exponentially-damped sine wave easing
|
||||
float ElasticIn(float p);
|
||||
float ElasticOut(float p);
|
||||
float ElasticInOut(float p);
|
||||
|
||||
// Overshooting cubic easing;
|
||||
float BackIn(float p);
|
||||
float BackOut(float p);
|
||||
float BackInOut(float p);
|
||||
|
||||
// Exponentially-decaying bounce easing
|
||||
float BounceIn(float p);
|
||||
float BounceOut(float p);
|
||||
float BounceInOut(float p);
|
||||
} // namespace easing
|
||||
|
||||
class Animator {
|
||||
public:
|
||||
Animator(float* from,
|
||||
float to = 0.f,
|
||||
Duration duration = std::chrono::milliseconds(250),
|
||||
easing::Function easing_function = easing::Linear,
|
||||
Duration delay = std::chrono::milliseconds(0));
|
||||
|
||||
void OnAnimation(Params&);
|
||||
|
||||
float to() const { return to_; }
|
||||
|
||||
private:
|
||||
float* value_;
|
||||
float from_;
|
||||
float to_;
|
||||
Duration duration_;
|
||||
easing::Function easing_function_;
|
||||
Duration current_;
|
||||
};
|
||||
|
||||
} // namespace animation
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_ANIMATION_HPP */
|
||||
@@ -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 <memory>
|
||||
|
||||
namespace ftxui {
|
||||
class CapturedMouseInterface {
|
||||
public:
|
||||
virtual ~CapturedMouseInterface() = default;
|
||||
};
|
||||
using CapturedMouse = std::unique_ptr<CapturedMouseInterface>;
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_CAPTURED_MOUSE_HPP */
|
||||
@@ -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 <functional> // for function
|
||||
#include <memory> // for make_shared, shared_ptr
|
||||
#include <string> // for wstring
|
||||
#include <utility> // for forward
|
||||
#include <vector> // 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 <class T, class... Args>
|
||||
std::shared_ptr<T> Make(Args&&... args) {
|
||||
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Pipe operator to decorate components.
|
||||
using ComponentDecorator = std::function<Component(Component)>;
|
||||
using ElementDecorator = std::function<Element(Element)>;
|
||||
Component operator|(Component component, ComponentDecorator decorator);
|
||||
Component operator|(Component component, ElementDecorator decorator);
|
||||
Component& operator|=(Component& component, ComponentDecorator decorator);
|
||||
Component& operator|=(Component& component, ElementDecorator decorator);
|
||||
|
||||
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<void()> 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 <typename T>
|
||||
Component Slider(SliderOption<T> options);
|
||||
|
||||
// Shorthand without the `SliderOption` constructor:
|
||||
Component Slider(ConstStringRef label,
|
||||
Ref<int> value,
|
||||
ConstRef<int> min = 0,
|
||||
ConstRef<int> max = 100,
|
||||
ConstRef<int> increment = 5);
|
||||
Component Slider(ConstStringRef label,
|
||||
Ref<float> value,
|
||||
ConstRef<float> min = 0.f,
|
||||
ConstRef<float> max = 100.f,
|
||||
ConstRef<float> increment = 5.f);
|
||||
Component Slider(ConstStringRef label,
|
||||
Ref<long> value,
|
||||
ConstRef<long> min = 0l,
|
||||
ConstRef<long> max = 100l,
|
||||
ConstRef<long> increment = 5l);
|
||||
|
||||
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<Element()>);
|
||||
Component Renderer(std::function<Element()>);
|
||||
Component Renderer(std::function<Element(bool /* focused */)>);
|
||||
ComponentDecorator Renderer(ElementDecorator);
|
||||
|
||||
Component CatchEvent(Component child, std::function<bool(Event)>);
|
||||
ComponentDecorator CatchEvent(std::function<bool(Event)> on_event);
|
||||
|
||||
Component Maybe(Component, const bool* show);
|
||||
Component Maybe(Component, std::function<bool()>);
|
||||
ComponentDecorator Maybe(const bool* show);
|
||||
ComponentDecorator Maybe(std::function<bool()>);
|
||||
|
||||
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<bool> show = false);
|
||||
|
||||
Component Hoverable(Component component, bool* hover);
|
||||
Component Hoverable(Component component,
|
||||
std::function<void()> on_enter,
|
||||
std::function<void()> on_leave);
|
||||
Component Hoverable(Component component, //
|
||||
std::function<void(bool)> on_change);
|
||||
ComponentDecorator Hoverable(bool* hover);
|
||||
ComponentDecorator Hoverable(std::function<void()> on_enter,
|
||||
std::function<void()> on_leave);
|
||||
ComponentDecorator Hoverable(std::function<void(bool)> on_change);
|
||||
|
||||
Component Window(WindowOptions option);
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_HPP */
|
||||
@@ -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 <memory> // for unique_ptr
|
||||
#include <vector> // 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<ComponentBase>;
|
||||
using Components = std::vector<Component>;
|
||||
|
||||
/// @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 */
|
||||
@@ -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 <chrono> // for milliseconds
|
||||
#include <ftxui/component/animation.hpp> // for Duration, QuadraticInOut, Function
|
||||
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Left, Direction::Right, Direction::Down
|
||||
#include <ftxui/dom/elements.hpp> // for Element, separator
|
||||
#include <ftxui/util/ref.hpp> // for Ref, ConstRef, StringRef
|
||||
#include <functional> // for function
|
||||
#include <optional> // for optional
|
||||
#include <string> // 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<Element(const EntryState& state)> 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<int> selected = 0; ///> The index of the selected entry.
|
||||
|
||||
// Style:
|
||||
UnderlineOption underline;
|
||||
MenuEntryOption entries_option;
|
||||
Direction direction = Direction::Down;
|
||||
std::function<Element()> elements_prefix;
|
||||
std::function<Element()> elements_infix;
|
||||
std::function<Element()> elements_postfix;
|
||||
|
||||
// Observers:
|
||||
std::function<void()> on_change; ///> Called when the selected entry changes.
|
||||
std::function<void()> on_enter; ///> Called when the user presses enter.
|
||||
Ref<int> focused_entry = 0;
|
||||
};
|
||||
|
||||
/// @brief Option for the AnimatedButton component.
|
||||
/// @ingroup component
|
||||
struct ButtonOption {
|
||||
// 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<void()> on_click = [] {};
|
||||
|
||||
// Style:
|
||||
std::function<Element(const EntryState&)> transform;
|
||||
AnimatedColorsOption animated_colors;
|
||||
};
|
||||
|
||||
/// @brief Option for the Checkbox component.
|
||||
/// @ingroup component
|
||||
struct CheckboxOption {
|
||||
// Standard constructors:
|
||||
static CheckboxOption Simple();
|
||||
|
||||
ConstStringRef label = "Checkbox";
|
||||
|
||||
Ref<bool> checked = false;
|
||||
|
||||
// Style:
|
||||
std::function<Element(const EntryState&)> transform;
|
||||
|
||||
// Observer:
|
||||
/// Called when the user change the state.
|
||||
std::function<void()> 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<Element(InputState)> transform;
|
||||
Ref<bool> password = false; /// < Obscure the input content using '*'.
|
||||
Ref<bool> multiline = true; /// < Whether the input can be multiline.
|
||||
|
||||
/// Called when the content changes.
|
||||
std::function<void()> on_change = [] {};
|
||||
/// Called when the user presses enter.
|
||||
std::function<void()> on_enter = [] {};
|
||||
|
||||
// The char position of the cursor:
|
||||
Ref<int> cursor_position = 0;
|
||||
};
|
||||
|
||||
/// @brief Option for the Radiobox component.
|
||||
/// @ingroup component
|
||||
struct RadioboxOption {
|
||||
// Standard constructors:
|
||||
static RadioboxOption Simple();
|
||||
|
||||
// Content:
|
||||
ConstStringListRef entries;
|
||||
Ref<int> selected = 0;
|
||||
|
||||
// Style:
|
||||
std::function<Element(const EntryState&)> transform;
|
||||
|
||||
// Observers:
|
||||
/// Called when the selected entry changes.
|
||||
std::function<void()> on_change = [] {};
|
||||
Ref<int> focused_entry = 0;
|
||||
};
|
||||
|
||||
struct ResizableSplitOption {
|
||||
Component main;
|
||||
Component back;
|
||||
Ref<Direction> direction = Direction::Left;
|
||||
Ref<int> main_size =
|
||||
(direction() == Direction::Left || direction() == Direction::Right) ? 20
|
||||
: 10;
|
||||
std::function<Element()> separator_func = [] { return ::ftxui::separator(); };
|
||||
};
|
||||
|
||||
// @brief Option for the `Slider` component.
|
||||
// @ingroup component
|
||||
template <typename T>
|
||||
struct SliderOption {
|
||||
Ref<T> value;
|
||||
ConstRef<T> min = T(0);
|
||||
ConstRef<T> max = T(100);
|
||||
ConstRef<T> increment = (max() - min()) / 20;
|
||||
Direction direction = Direction::Right;
|
||||
Color color_active = Color::White;
|
||||
Color color_inactive = Color::GrayDark;
|
||||
};
|
||||
|
||||
// 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<int> left = 0; /// < The left side position of the window.
|
||||
Ref<int> top = 0; /// < The top side position of the window.
|
||||
Ref<int> width = 20; /// < The width of the window.
|
||||
Ref<int> height = 10; /// < The height of the window.
|
||||
|
||||
Ref<bool> resize_left = true; /// < Can the left side be resized?
|
||||
Ref<bool> resize_right = true; /// < Can the right side be resized?
|
||||
Ref<bool> resize_top = true; /// < Can the top side be resized?
|
||||
Ref<bool> resize_down = true; /// < Can the down side be resized?
|
||||
|
||||
/// An optional function to customize how the window looks like:
|
||||
std::function<Element(const WindowRenderState&)> render;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP */
|
||||
@@ -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 <ftxui/component/mouse.hpp> // for Mouse
|
||||
#include <functional>
|
||||
#include <string> // for string, operator==
|
||||
#include <vector>
|
||||
|
||||
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 */
|
||||
@@ -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 <memory> // for shared_ptr
|
||||
|
||||
#include "ftxui/component/component_base.hpp" // for ComponentBase
|
||||
|
||||
namespace ftxui {
|
||||
class ComponentBase;
|
||||
|
||||
using Component = std::shared_ptr<ComponentBase>;
|
||||
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
|
||||
@@ -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 */
|
||||
@@ -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 <algorithm> // for copy, max
|
||||
#include <atomic> // for atomic, __atomic_base
|
||||
#include <condition_variable> // for condition_variable
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory> // for unique_ptr, make_unique
|
||||
#include <mutex> // for mutex, unique_lock
|
||||
#include <queue> // for queue
|
||||
#include <utility> // for move
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
// Usage:
|
||||
//
|
||||
// Initialization:
|
||||
// ---------------
|
||||
//
|
||||
// auto receiver = MakeReceiver<std:string>();
|
||||
// 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 T> class SenderImpl;
|
||||
template<class T> class ReceiverImpl;
|
||||
|
||||
template<class T> using Sender = std::unique_ptr<SenderImpl<T>>;
|
||||
template<class T> using Receiver = std::unique_ptr<ReceiverImpl<T>>;
|
||||
template<class T> Receiver<T> MakeReceiver();
|
||||
// clang-format on
|
||||
|
||||
// ---- Implementation part ----
|
||||
|
||||
template <class T>
|
||||
class SenderImpl {
|
||||
public:
|
||||
void Send(T t) { receiver_->Receive(std::move(t)); }
|
||||
~SenderImpl() { receiver_->ReleaseSender(); }
|
||||
|
||||
Sender<T> Clone() { return receiver_->MakeSender(); }
|
||||
|
||||
private:
|
||||
friend class ReceiverImpl<T>;
|
||||
SenderImpl(ReceiverImpl<T>* consumer) : receiver_(consumer) {}
|
||||
ReceiverImpl<T>* receiver_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ReceiverImpl {
|
||||
public:
|
||||
Sender<T> MakeSender() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
senders_++;
|
||||
return std::unique_ptr<SenderImpl<T>>(new SenderImpl<T>(this));
|
||||
}
|
||||
ReceiverImpl() { senders_ = 0; }
|
||||
|
||||
bool Receive(T* t) {
|
||||
while (senders_ || !queue_.empty()) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (queue_.empty())
|
||||
notifier_.wait(lock);
|
||||
if (queue_.empty())
|
||||
continue;
|
||||
*t = std::move(queue_.front());
|
||||
queue_.pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReceiveNonBlocking(T* t) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (queue_.empty())
|
||||
return false;
|
||||
*t = queue_.front();
|
||||
queue_.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasPending() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return !queue_.empty();
|
||||
}
|
||||
|
||||
bool HasQuitted() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return queue_.empty() && !senders_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class SenderImpl<T>;
|
||||
|
||||
void Receive(T t) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
queue_.push(std::move(t));
|
||||
}
|
||||
notifier_.notify_one();
|
||||
}
|
||||
|
||||
void ReleaseSender() {
|
||||
senders_--;
|
||||
notifier_.notify_one();
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::queue<T> queue_;
|
||||
std::condition_variable notifier_;
|
||||
std::atomic<int> senders_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Receiver<T> MakeReceiver() {
|
||||
return std::make_unique<ReceiverImpl<T>>();
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_COMPONENT_RECEIVER_HPP_
|
||||
@@ -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 <atomic> // for atomic
|
||||
#include <ftxui/component/receiver.hpp> // for Receiver, Sender
|
||||
#include <functional> // for function
|
||||
#include <memory> // for shared_ptr
|
||||
#include <string> // for string
|
||||
#include <thread> // for thread
|
||||
#include <variant> // for variant
|
||||
|
||||
#include "ftxui/component/animation.hpp" // for TimePoint
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
|
||||
#include "ftxui/component/event.hpp" // for Event
|
||||
#include "ftxui/component/task.hpp" // for Task, Closure
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
|
||||
namespace ftxui {
|
||||
class ComponentBase;
|
||||
class Loop;
|
||||
struct Event;
|
||||
|
||||
using Component = std::shared_ptr<ComponentBase>;
|
||||
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> task_sender_;
|
||||
Receiver<Task> task_receiver_;
|
||||
|
||||
std::string set_cursor_position;
|
||||
std::string reset_cursor_position;
|
||||
|
||||
std::atomic<bool> quit_ = false;
|
||||
std::thread event_listener_;
|
||||
std::thread animation_listener_;
|
||||
bool animation_requested_ = false;
|
||||
animation::TimePoint previous_animation_time_;
|
||||
|
||||
int cursor_x_ = 1;
|
||||
int cursor_y_ = 1;
|
||||
|
||||
bool mouse_captured = false;
|
||||
bool previous_frame_resized_ = false;
|
||||
|
||||
bool frame_valid_ = false;
|
||||
|
||||
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 */
|
||||
@@ -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 <functional>
|
||||
#include <variant>
|
||||
#include "ftxui/component/event.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
class AnimationTask {};
|
||||
using Closure = std::function<void()>;
|
||||
using Task = std::variant<Event, Closure, AnimationTask>;
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_COMPONENT_ANIMATION_HPP
|
||||
@@ -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 <cstddef> // for size_t
|
||||
#include <functional> // for function
|
||||
#include <string> // for string
|
||||
#include <unordered_map> // 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<void(Pixel&)>;
|
||||
|
||||
// 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<XY, Cell, XYHash> storage_;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_DOM_CANVAS_HPP
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 <functional>
|
||||
#include <memory>
|
||||
|
||||
#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<Node>;
|
||||
using Elements = std::vector<Element>;
|
||||
using Decorator = std::function<Element(Element)>;
|
||||
using GraphFunction = std::function<std::vector<int>(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<Canvas>);
|
||||
Element canvas(int width, int height, std::function<void(Canvas&)>);
|
||||
Element canvas(std::function<void(Canvas&)>);
|
||||
|
||||
// -- 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<Elements> 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
|
||||
@@ -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
|
||||
@@ -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 <optional>
|
||||
#include <vector>
|
||||
|
||||
#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<float> position;
|
||||
};
|
||||
std::vector<Stop> 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
|
||||
@@ -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 <memory> // for shared_ptr
|
||||
#include <vector> // 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<Node>;
|
||||
using Elements = std::vector<Element>;
|
||||
|
||||
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
|
||||
@@ -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
|
||||
@@ -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 <memory>
|
||||
#include <string> // for string
|
||||
#include <vector> // 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<std::vector<std::string>>);
|
||||
Table(std::vector<std::vector<Element>>);
|
||||
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<std::vector<Element>>);
|
||||
friend TableSelection;
|
||||
std::vector<std::vector<Element>> 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 */
|
||||
@@ -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 <type_traits>
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
template <class T>
|
||||
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 <class... Args>
|
||||
Elements unpack(Args... args) {
|
||||
std::vector<Element> vec;
|
||||
(Merge(vec, std::move(args)), ...);
|
||||
return vec;
|
||||
}
|
||||
|
||||
// Make |container| able to take any number of argments.
|
||||
#define TAKE_ANY_ARGS(container) \
|
||||
template <class... Args> \
|
||||
Element container(Args... children) { \
|
||||
return container(unpack(std::forward<Args>(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
|
||||
@@ -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
|
||||
@@ -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 <cstdint> // for uint8_t
|
||||
#include <string> // for string
|
||||
#include <vector> // 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
|
||||
@@ -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 <cstdint>
|
||||
#include <ftxui/screen/color.hpp>
|
||||
|
||||
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
|
||||
@@ -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 <string>
|
||||
|
||||
namespace ftxui {
|
||||
int wchar_width(wchar_t);
|
||||
int wstring_width(const std::wstring&);
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_SCREEN_DEPRECATED_HPP
|
||||
@@ -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 <cstdint> // for uint8_t
|
||||
#include <memory>
|
||||
#include <string> // for string, basic_string, allocator
|
||||
#include <vector> // 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<std::vector<Pixel>> pixels_;
|
||||
Cursor cursor_;
|
||||
std::vector<std::string> hyperlinks_ = {""};
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_SCREEN_SCREEN_HPP
|
||||
@@ -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 <stddef.h> // for size_t
|
||||
#include <cstdint> // for uint8_t
|
||||
#include <string> // for string, wstring, to_string
|
||||
#include <vector> // for vector
|
||||
|
||||
namespace ftxui {
|
||||
std::string to_string(const std::wstring& s);
|
||||
std::wstring to_wstring(const std::string& s);
|
||||
|
||||
template <typename T>
|
||||
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<std::string> 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<int> CellToGlyphIndex(const std::string& input);
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#include "ftxui/screen/deprecated.hpp"
|
||||
|
||||
#endif /* end of include guard: FTXUI_SCREEN_STRING_HPP */
|
||||
@@ -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
|
||||
@@ -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 <utility>
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
/// Assign a value to a variable, reset its old value when going out of scope.
|
||||
template <typename T>
|
||||
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 */
|
||||
@@ -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 <ftxui/screen/string.hpp>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
/// @brief An adapter. Own or reference an immutable object.
|
||||
template <typename T>
|
||||
class ConstRef {
|
||||
public:
|
||||
ConstRef() = default;
|
||||
ConstRef(const ConstRef<T>&) = default;
|
||||
ConstRef(ConstRef<T>&&) = default;
|
||||
ConstRef(T t) : variant_(std::move(t)) {}
|
||||
ConstRef(const T* t) : variant_(t) {}
|
||||
|
||||
// Make a "reseatable" reference
|
||||
ConstRef<T>& operator=(const ConstRef<T>&) = default;
|
||||
|
||||
// Accessors:
|
||||
const T& operator()() const { return *Address(); }
|
||||
const T& operator*() const { return *Address(); }
|
||||
const T* operator->() const { return Address(); }
|
||||
|
||||
private:
|
||||
std::variant<T, const T*> variant_ = T{};
|
||||
|
||||
const T* Address() const {
|
||||
return std::holds_alternative<T>(variant_) ? &std::get<T>(variant_)
|
||||
: std::get<const T*>(variant_);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief An adapter. Own or reference an mutable object.
|
||||
template <typename T>
|
||||
class Ref {
|
||||
public:
|
||||
Ref() = default;
|
||||
Ref(const Ref<T>&) = default;
|
||||
Ref(Ref<T>&&) = default;
|
||||
Ref(T t) : variant_(std::move(t)) {}
|
||||
Ref(T* t) : variant_(t) {}
|
||||
|
||||
// Make a "reseatable" reference.
|
||||
Ref<T>& operator=(const Ref<T>&) = 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<T, T*> variant_ = T{};
|
||||
|
||||
const T* Address() const {
|
||||
return std::holds_alternative<T>(variant_) ? &std::get<T>(variant_)
|
||||
: std::get<T*>(variant_);
|
||||
}
|
||||
T* Address() {
|
||||
return std::holds_alternative<T>(variant_) ? &std::get<T>(variant_)
|
||||
: std::get<T*>(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<std::string> {
|
||||
public:
|
||||
using Ref<std::string>::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<std::string> {
|
||||
public:
|
||||
using ConstRef<std::string>::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<std::string>* ref) : ref_(ref) {}
|
||||
ConstStringListRef(const std::vector<std::wstring>* 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<std::string>* ref_ = nullptr;
|
||||
const std::vector<std::wstring>* ref_wide_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_UTIL_REF_HPP */
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
14
src/main.cpp
14
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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
482
src/tui/tui.cpp
Normal file
482
src/tui/tui.cpp
Normal file
@@ -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 <ftxui/component/component.hpp>
|
||||
#include <ftxui/component/screen_interactive.hpp>
|
||||
#include <ftxui/dom/elements.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <system_error>
|
||||
|
||||
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<std::string> Tui::Tokenize(const std::string &s) {
|
||||
std::vector<std::string> 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 <module> <file> <mentor|altium|ods> 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<System>();
|
||||
Print("system created.");
|
||||
}};
|
||||
commands["load"] = {
|
||||
{{"module name", false},
|
||||
{"filename", true},
|
||||
{"import type [mentor|altium|ods]", false}},
|
||||
[this](const std::vector<std::string> &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<std::vector<std::string>>(
|
||||
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<std::string> &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<std::string> &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<std::string> 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<std::string> names;
|
||||
std::vector<bool> 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);
|
||||
}
|
||||
75
src/tui/tui.hpp
Normal file
75
src/tui/tui.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef _TUI_HPP_
|
||||
#define _TUI_HPP_
|
||||
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class System;
|
||||
|
||||
class Tui {
|
||||
struct Prompt {
|
||||
std::string question;
|
||||
std::function<void(const std::string &)> on_answer;
|
||||
bool path_completion = false;
|
||||
};
|
||||
|
||||
struct CommandSpec {
|
||||
struct Param {
|
||||
std::string name;
|
||||
bool path_completion = false;
|
||||
};
|
||||
std::vector<Param> params;
|
||||
std::function<void(const std::vector<std::string> &)> action;
|
||||
};
|
||||
|
||||
std::vector<std::string> history;
|
||||
std::vector<std::string> output;
|
||||
std::string input;
|
||||
int cursor_pos;
|
||||
int history_idx;
|
||||
bool quit;
|
||||
|
||||
std::unique_ptr<System> sys;
|
||||
std::deque<Prompt> pending;
|
||||
std::map<std::string, CommandSpec> commands;
|
||||
|
||||
int screen_idx;
|
||||
std::vector<std::string> search_modules;
|
||||
std::vector<std::string> 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<std::string> &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<std::string> Tokenize(const std::string &s);
|
||||
};
|
||||
|
||||
#endif // _TUI_HPP_
|
||||
Reference in New Issue
Block a user