From 7e5cd23b4c47972b70b99c39617d6e38f05d1b3a Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Mon, 13 Dec 2021 11:38:31 +0100 Subject: [PATCH] Add focusPosition[relative](x,y) (#280) It allows when using inside a frame, to scroll the view toward a particular position. This resolves: https://github.com/ArthurSonzogni/FTXUI/issues/125 --- CHANGELOG.md | 7 ++ CMakeLists.txt | 1 + examples/component/CMakeLists.txt | 1 + examples/component/focus.cpp | 72 +++++++++++++++++++++ include/ftxui/dom/elements.hpp | 2 + src/ftxui/dom/focus.cpp | 103 ++++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+) create mode 100644 examples/component/focus.cpp create mode 100644 src/ftxui/dom/focus.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index fd5554c..86c590b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,13 @@ unreleased (development) - `paragraphAlignRight` - `paragraphAlignJustify` - Add the helper elements based on `flexbox`: `hflow()`, `vflow()`. +- Add: `focusPositionRelative` and `focusPosition` + +### Bug + +#### Component +- `Input` shouldn't take focus when hovered by the mouse. +- Modifying `Input`'s during on_enter/on_change event is now working correctly. ### Bug diff --git a/CMakeLists.txt b/CMakeLists.txt index 936df98..b288f12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ add_library(dom src/ftxui/dom/flexbox_config.cpp src/ftxui/dom/flexbox_helper.cpp src/ftxui/dom/flexbox_helper.hpp + src/ftxui/dom/focus.cpp src/ftxui/dom/frame.cpp src/ftxui/dom/gauge.cpp src/ftxui/dom/graph.cpp diff --git a/examples/component/CMakeLists.txt b/examples/component/CMakeLists.txt index 23ec54a..24ea2bf 100644 --- a/examples/component/CMakeLists.txt +++ b/examples/component/CMakeLists.txt @@ -10,6 +10,7 @@ example(gallery) example(homescreen) example(input) example(maybe) +example(focus) example(menu) example(menu2) example(menu_entries) diff --git a/examples/component/focus.cpp b/examples/component/focus.cpp new file mode 100644 index 0000000..c1a5c56 --- /dev/null +++ b/examples/component/focus.cpp @@ -0,0 +1,72 @@ +#include // for size_t +#include // for shared_ptr, __shared_ptr_access, allocator +#include // for string, basic_string, to_string, operator+, char_traits +#include // for vector + +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for Radiobox, Vertical, Checkbox, Horizontal, Renderer, ResizableSplitBottom, ResizableSplitRight +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for text, window, operator|, vbox, hbox, Element, flexbox, bgcolor, filler, flex, size, border, hcenter, color, EQUAL, bold, dim, notflex, xflex_grow, yflex_grow, HEIGHT, WIDTH +#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig, FlexboxConfig::AlignContent, FlexboxConfig::JustifyContent, FlexboxConfig::AlignContent::Center, FlexboxConfig::AlignItems, FlexboxConfig::Direction, FlexboxConfig::JustifyContent::Center, FlexboxConfig::Wrap +#include "ftxui/screen/color.hpp" // for Color, Color::Black + +using namespace ftxui; + +Element make_box(int x, int y) { + std::string title = "(" + std::to_string(x) + ", " + std::to_string(y) + ")"; + return text(title) | center | size(WIDTH, EQUAL, 18) | + size(HEIGHT, EQUAL, 9) | border | + bgcolor(Color::HSV(x * 255 / 15, 255, y * 255 / 15)); +}; + +Element make_grid() { + std::vector rows; + for (int i = 0; i < 15; i++) { + std::vector cols; + for (int j = 0; j < 15; j++) { + cols.push_back(make_box(i, j)); + } + rows.push_back(cols); + } + + return gridbox(rows); +}; + +int main(int argc, const char* argv[]) { + float focus_x = 0.0f; + float focus_y = 0.0f; + + auto slider_x = Slider("x", &focus_x, 0.f, 1.f, 0.05f); + auto slider_y = Slider("y", &focus_y, 0.f, 1.f, 0.05f); + + auto renderer = Renderer( + Container::Vertical({ + slider_x, + slider_y, + }), + [&] { + auto title = "focusPositionRelative(" + // + std::to_string(focus_x) + ", " + // + std::to_string(focus_y) + ")"; // + return vbox({ + text(title), + separator(), + slider_x->Render(), + slider_y->Render(), + separator(), + make_grid() | focusPositionRelative(focus_x, focus_y) | + frame | flex, + }) | + border; + }); + + auto screen = ScreenInteractive::Fullscreen(); + screen.Loop(renderer); + + return 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. diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index a9e7967..d3e53ed 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -68,6 +68,8 @@ Decorator color(Color); Decorator bgcolor(Color); Element color(Color, Element); Element bgcolor(Color, Element); +Decorator focusPosition(int x, int y); +Decorator focusPositionRelative(float x, float y); // --- Layout is // Horizontal, Vertical or stacked set of elements. diff --git a/src/ftxui/dom/focus.cpp b/src/ftxui/dom/focus.cpp new file mode 100644 index 0000000..8470ecd --- /dev/null +++ b/src/ftxui/dom/focus.cpp @@ -0,0 +1,103 @@ +#include // for make_shared +#include // for move + +#include "ftxui/dom/elements.hpp" // for Element, bold +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/screen.hpp" // for Pixel, Screen + +namespace ftxui { + +namespace { + +} // namespace + +/// @brief Used inside a `frame`, this force the view to be scrolled toward a +/// a given position. The position is expressed in proportion of the requested +/// size. +/// +/// For instance: +/// - (0, 0) means that the view is scrolled toward the upper left. +/// - (1, 0) means that the view is scrolled toward the upper right. +/// - (0, 1) means that the view is scrolled toward the bottom left. +/// @ingroup dom +/// +/// ### Example +/// +/// ```cpp +/// Element document = huge_document() +/// | focusPositionRelative(0.f, 1.f) +/// | frame; +/// ``` +Decorator focusPositionRelative(float x, float y) { + class Impl : public NodeDecorator { + public: + Impl(Element child, float x, float y) + : NodeDecorator(child), x_(x), y_(y) {} + + void ComputeRequirement() override { + NodeDecorator::ComputeRequirement(); + requirement_.selection = Requirement::Selection::NORMAL; + + Box& box = requirement_.selected_box; + box.x_min = requirement_.min_x * x_; + box.y_min = requirement_.min_y * y_; + box.x_max = requirement_.min_x * x_; + box.y_max = requirement_.min_y * y_; + } + + private: + const float x_; + const float y_; + }; + + return [x, y](Element child) { + return std::make_shared(std::move(child), x, y); + }; +} + +/// @brief Used inside a `frame`, this force the view to be scrolled toward a +/// a given position. The position is expressed in the numbers of cells. +/// +/// @ingroup dom +/// +/// ### Example +/// +/// ```cpp +/// Element document = huge_document() +/// | focusPosition(10, 10) +/// | frame; +/// ``` +Decorator focusPosition(int x, int y) { + class Impl : public NodeDecorator { + public: + Impl(Element child, float x, float y) + : NodeDecorator(child), x_(x), y_(y) {} + + void ComputeRequirement() override { + NodeDecorator::ComputeRequirement(); + requirement_.selection = Requirement::Selection::NORMAL; + + Box& box = requirement_.selected_box; + box.x_min = x_; + box.y_min = y_; + box.x_max = x_; + box.y_max = y_; + } + + private: + const int x_; + const int y_; + }; + + return [x, y](Element child) { + return std::make_shared(std::move(child), x, y); + }; +} + +} // namespace ftxui + +// 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.