Feature resizable spilt with custom separator (#583)

* Feature: ResizableSplit with custom separator

This resolves:
    https://github.com/ArthurSonzogni/FTXUI/issues/580

Co-authored-by: Pin Loon Lee <pinloon_0428@hotmail.com>
This commit is contained in:
Arthur Sonzogni 2023-03-09 20:21:23 +01:00 committed by ArthurSonzogni
parent d3ee655a90
commit eb313e0f2d
No known key found for this signature in database
GPG Key ID: 41D98248C074CD6C
15 changed files with 385 additions and 310 deletions

View File

@ -4,6 +4,14 @@ Changelog
current (development) current (development)
--------------------- ---------------------
### Component
- Feature: Support `ResizableSplit` with customizable separator.
- Breaking: MenuDirection enum is renamed Direction
###
- Breaking: Direction enum is renamed WidthOrHeight
- Breaking: GaugeDirection enum is renamed Direction
4.0.0 4.0.0
----- -----

View File

@ -42,6 +42,7 @@ add_library(screen
add_library(dom add_library(dom
include/ftxui/dom/canvas.hpp include/ftxui/dom/canvas.hpp
include/ftxui/dom/direction.hpp
include/ftxui/dom/elements.hpp include/ftxui/dom/elements.hpp
include/ftxui/dom/flexbox_config.hpp include/ftxui/dom/flexbox_config.hpp
include/ftxui/dom/node.hpp include/ftxui/dom/node.hpp

View File

@ -2,7 +2,8 @@
#include <cmath> // for sin #include <cmath> // for sin
#include <ftxui/component/component_base.hpp> // for ComponentBase #include <ftxui/component/component_base.hpp> // for ComponentBase
#include <ftxui/component/component_options.hpp> // for SliderOption #include <ftxui/component/component_options.hpp> // for SliderOption
#include <ftxui/dom/elements.hpp> // for size, GREATER_THAN, GaugeDirection, GaugeDirection::Up, HEIGHT #include <ftxui/dom/direction.hpp> // for Direction, Direction::Up
#include <ftxui/dom/elements.hpp> // for size, GREATER_THAN, HEIGHT
#include <ftxui/util/ref.hpp> // for ConstRef, Ref #include <ftxui/util/ref.hpp> // for ConstRef, Ref
#include <memory> // for shared_ptr, __shared_ptr_access #include <memory> // for shared_ptr, __shared_ptr_access
@ -26,7 +27,7 @@ int main(int argc, const char* argv[]) {
option.value = &values[i]; option.value = &values[i];
option.max = 100; option.max = 100;
option.increment = 5; option.increment = 5;
option.direction = GaugeDirection::Up; option.direction = Direction::Up;
layout_horizontal->Add(Slider<int>(option)); layout_horizontal->Add(Slider<int>(option));
/* In C++20: /* In C++20:
@ -34,7 +35,7 @@ int main(int argc, const char* argv[]) {
.value = &values[i], .value = &values[i],
.max = 100, .max = 100,
.increment = 5, .increment = 5,
.direction = GaugeDirection::Up, .direction = Direction::Up,
})); }));
*/ */
} }

View File

@ -92,6 +92,7 @@ Component ResizableSplitLeft(Component main, Component back, int* main_size);
Component ResizableSplitRight(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 ResizableSplitTop(Component main, Component back, int* main_size);
Component ResizableSplitBottom(Component main, Component back, int* main_size); Component ResizableSplitBottom(Component main, Component back, int* main_size);
Component ResizableSplit(ResizableSplitOption options);
Component Renderer(Component child, std::function<Element()>); Component Renderer(Component child, std::function<Element()>);
Component Renderer(std::function<Element()>); Component Renderer(std::function<Element()>);

View File

@ -3,12 +3,14 @@
#include <chrono> // for milliseconds #include <chrono> // for milliseconds
#include <ftxui/component/animation.hpp> // for Duration, QuadraticInOut, Function #include <ftxui/component/animation.hpp> // for Duration, QuadraticInOut, Function
#include <ftxui/dom/elements.hpp> // for Element, GaugeDirection, GaugeDirection::Right #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 #include <ftxui/util/ref.hpp> // for Ref, ConstRef
#include <functional> // for function #include <functional> // for function
#include <optional> // for optional #include <optional> // for optional
#include <string> // for string #include <string> // for string
#include "ftxui/component/component_base.hpp" // for Component
#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White #include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White
namespace ftxui { namespace ftxui {
@ -87,8 +89,7 @@ struct MenuOption {
// Style: // Style:
UnderlineOption underline; UnderlineOption underline;
MenuEntryOption entries; MenuEntryOption entries;
enum Direction { Up, Down, Left, Right }; Direction direction = Direction::Down;
Direction direction = Down;
std::function<Element()> elements_prefix; std::function<Element()> elements_prefix;
std::function<Element()> elements_infix; std::function<Element()> elements_infix;
std::function<Element()> elements_postfix; std::function<Element()> elements_postfix;
@ -164,6 +165,16 @@ struct RadioboxOption {
Ref<int> focused_entry = 0; 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. // @brief Option for the `Slider` component.
// @ingroup component // @ingroup component
template <typename T> template <typename T>
@ -172,7 +183,7 @@ struct SliderOption {
ConstRef<T> min = T(0); ConstRef<T> min = T(0);
ConstRef<T> max = T(100); ConstRef<T> max = T(100);
ConstRef<T> increment = (max() - min()) / 20; ConstRef<T> increment = (max() - min()) / 20;
GaugeDirection direction = GaugeDirection::Right; Direction direction = Direction::Right;
Color color_active = Color::White; Color color_active = Color::White;
Color color_inactive = Color::GrayDark; Color color_inactive = Color::GrayDark;
}; };

View File

@ -0,0 +1,17 @@
#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 // FTXUI_DOM_DIRECTION_HPP
// 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.

View File

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include "ftxui/dom/canvas.hpp" #include "ftxui/dom/canvas.hpp"
#include "ftxui/dom/direction.hpp"
#include "ftxui/dom/flexbox_config.hpp" #include "ftxui/dom/flexbox_config.hpp"
#include "ftxui/dom/node.hpp" #include "ftxui/dom/node.hpp"
#include "ftxui/screen/box.hpp" #include "ftxui/screen/box.hpp"
@ -21,7 +22,6 @@ using Decorator = std::function<Element(Element)>;
using GraphFunction = std::function<std::vector<int>(int, int)>; using GraphFunction = std::function<std::vector<int>(int, int)>;
enum BorderStyle { LIGHT, HEAVY, DOUBLE, ROUNDED, EMPTY }; enum BorderStyle { LIGHT, HEAVY, DOUBLE, ROUNDED, EMPTY };
enum class GaugeDirection { Left, Up, Right, Down };
// Pipe elements into decorator togethers. // Pipe elements into decorator togethers.
// For instance the next lines are equivalents: // For instance the next lines are equivalents:
@ -56,7 +56,7 @@ Element gaugeLeft(float progress);
Element gaugeRight(float progress); Element gaugeRight(float progress);
Element gaugeUp(float progress); Element gaugeUp(float progress);
Element gaugeDown(float progress); Element gaugeDown(float progress);
Element gaugeDirection(float progress, GaugeDirection); Element gaugeDirection(float progress, Direction direction);
Element border(Element); Element border(Element);
Element borderLight(Element); Element borderLight(Element);
Element borderHeavy(Element); Element borderHeavy(Element);
@ -124,9 +124,9 @@ Element notflex(Element); // Reset the flex attribute.
Element filler(); // A blank expandable element. Element filler(); // A blank expandable element.
// -- Size override; // -- Size override;
enum Direction { WIDTH, HEIGHT }; enum WidthOrHeight { WIDTH, HEIGHT };
enum Constraint { LESS_THAN, EQUAL, GREATER_THAN }; enum Constraint { LESS_THAN, EQUAL, GREATER_THAN };
Decorator size(Direction, Constraint, int value); Decorator size(WidthOrHeight, Constraint, int value);
// --- Frame --- // --- Frame ---
// A frame is a scrollable area. The internal area is potentially larger than // A frame is a scrollable area. The internal area is potentially larger than

View File

@ -1,5 +1,6 @@
#include <algorithm> // for max, fill_n, reverse #include <algorithm> // for max, fill_n, reverse
#include <chrono> // for milliseconds #include <chrono> // for milliseconds
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <functional> // for function #include <functional> // for function
#include <memory> // for allocator_traits<>::value_type, swap #include <memory> // for allocator_traits<>::value_type, swap
#include <string> // for operator+, string #include <string> // for operator+, string
@ -10,7 +11,7 @@
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
#include "ftxui/component/component.hpp" // for Make, Menu, MenuEntry, Toggle #include "ftxui/component/component.hpp" // for Make, Menu, MenuEntry, Toggle
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for MenuOption, MenuEntryOption, MenuOption::Direction, UnderlineOption, AnimatedColorOption, AnimatedColorsOption, EntryState, MenuOption::Down, MenuOption::Left, MenuOption::Right, MenuOption::Up #include "ftxui/component/component_options.hpp" // for MenuOption, MenuEntryOption, UnderlineOption, AnimatedColorOption, AnimatedColorsOption, EntryState
#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp, Event::End, Event::Home, Event::PageDown, Event::PageUp, Event::Return, Event::Tab, Event::TabReverse #include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp, Event::End, Event::Home, Event::PageDown, Event::PageUp, Event::Return, Event::Tab, Event::TabReverse
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Released, Mouse::WheelDown, Mouse::WheelUp, Mouse::None #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Released, Mouse::WheelDown, Mouse::WheelUp, Mouse::None
#include "ftxui/component/screen_interactive.hpp" // for Component #include "ftxui/component/screen_interactive.hpp" // for Component
@ -36,25 +37,25 @@ Element DefaultOptionTransform(const EntryState& state) {
return e; return e;
} }
bool IsInverted(MenuOption::Direction direction) { bool IsInverted(Direction direction) {
switch (direction) { switch (direction) {
case MenuOption::Direction::Up: case Direction::Up:
case MenuOption::Direction::Left: case Direction::Left:
return true; return true;
case MenuOption::Direction::Down: case Direction::Down:
case MenuOption::Direction::Right: case Direction::Right:
return false; return false;
} }
return false; // NOT_REACHED() return false; // NOT_REACHED()
} }
bool IsHorizontal(MenuOption::Direction direction) { bool IsHorizontal(Direction direction) {
switch (direction) { switch (direction) {
case MenuOption::Direction::Left: case Direction::Left:
case MenuOption::Direction::Right: case Direction::Right:
return true; return true;
case MenuOption::Direction::Down: case Direction::Down:
case MenuOption::Direction::Up: case Direction::Up:
return false; return false;
} }
return false; // NOT_REACHED() return false; // NOT_REACHED()
@ -178,56 +179,56 @@ class MenuBase : public ComponentBase {
void OnUp() { void OnUp() {
switch (option_->direction) { switch (option_->direction) {
case MenuOption::Direction::Up: case Direction::Up:
(*selected_)++; (*selected_)++;
break; break;
case MenuOption::Direction::Down: case Direction::Down:
(*selected_)--; (*selected_)--;
break; break;
case MenuOption::Direction::Left: case Direction::Left:
case MenuOption::Direction::Right: case Direction::Right:
break; break;
} }
} }
void OnDown() { void OnDown() {
switch (option_->direction) { switch (option_->direction) {
case MenuOption::Direction::Up: case Direction::Up:
(*selected_)--; (*selected_)--;
break; break;
case MenuOption::Direction::Down: case Direction::Down:
(*selected_)++; (*selected_)++;
break; break;
case MenuOption::Direction::Left: case Direction::Left:
case MenuOption::Direction::Right: case Direction::Right:
break; break;
} }
} }
void OnLeft() { void OnLeft() {
switch (option_->direction) { switch (option_->direction) {
case MenuOption::Direction::Left: case Direction::Left:
(*selected_)++; (*selected_)++;
break; break;
case MenuOption::Direction::Right: case Direction::Right:
(*selected_)--; (*selected_)--;
break; break;
case MenuOption::Direction::Down: case Direction::Down:
case MenuOption::Direction::Up: case Direction::Up:
break; break;
} }
} }
void OnRight() { void OnRight() {
switch (option_->direction) { switch (option_->direction) {
case MenuOption::Direction::Left: case Direction::Left:
(*selected_)--; (*selected_)--;
break; break;
case MenuOption::Direction::Right: case Direction::Right:
(*selected_)++; (*selected_)++;
break; break;
case MenuOption::Direction::Down: case Direction::Down:
case MenuOption::Direction::Up: case Direction::Up:
break; break;
} }
} }

View File

@ -1,5 +1,6 @@
#include <gtest/gtest.h> // for Test, EXPECT_EQ, Message, TestPartResult, TestInfo (ptr only), TEST #include <gtest/gtest.h> // for Test, EXPECT_EQ, Message, TestPartResult, TestInfo (ptr only), TEST
#include <chrono> // for operator""s, chrono_literals #include <chrono> // for operator""s, chrono_literals
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <memory> // for __shared_ptr_access, shared_ptr, allocator #include <memory> // for __shared_ptr_access, shared_ptr, allocator
#include <string> // for string, basic_string #include <string> // for string, basic_string
#include <vector> // for vector #include <vector> // for vector
@ -7,7 +8,7 @@
#include "ftxui/component/animation.hpp" // for Duration, Params #include "ftxui/component/animation.hpp" // for Duration, Params
#include "ftxui/component/component.hpp" // for Menu #include "ftxui/component/component.hpp" // for Menu
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for MenuOption, MenuOption::Down, MenuOption::Left, MenuOption::Right, MenuOption::Up #include "ftxui/component/component_options.hpp" // for MenuOption
#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp, Event::Return #include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp, Event::Return
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
@ -53,7 +54,7 @@ TEST(MenuTest, DirectionDown) {
auto menu = Menu(&entries, &selected, &option); auto menu = Menu(&entries, &selected, &option);
selected = 0; selected = 0;
option.direction = MenuOption::Down; option.direction = Direction::Down;
Screen screen(4, 3); Screen screen(4, 3);
Render(screen, menu->Render()); Render(screen, menu->Render());
EXPECT_EQ(screen.ToString(), EXPECT_EQ(screen.ToString(),
@ -80,7 +81,7 @@ TEST(MenuTest, DirectionsUp) {
std::vector<std::string> entries = {"1", "2", "3"}; std::vector<std::string> entries = {"1", "2", "3"};
MenuOption option; MenuOption option;
auto menu = Menu(&entries, &selected, &option); auto menu = Menu(&entries, &selected, &option);
option.direction = MenuOption::Up; option.direction = Direction::Up;
Screen screen(4, 3); Screen screen(4, 3);
Render(screen, menu->Render()); Render(screen, menu->Render());
EXPECT_EQ(screen.ToString(), EXPECT_EQ(screen.ToString(),
@ -106,7 +107,7 @@ TEST(MenuTest, DirectionsRight) {
std::vector<std::string> entries = {"1", "2", "3"}; std::vector<std::string> entries = {"1", "2", "3"};
MenuOption option; MenuOption option;
auto menu = Menu(&entries, &selected, &option); auto menu = Menu(&entries, &selected, &option);
option.direction = MenuOption::Right; option.direction = Direction::Right;
Screen screen(10, 1); Screen screen(10, 1);
Render(screen, menu->Render()); Render(screen, menu->Render());
EXPECT_EQ(screen.ToString(), EXPECT_EQ(screen.ToString(),
@ -132,7 +133,7 @@ TEST(MenuTest, DirectionsLeft) {
std::vector<std::string> entries = {"1", "2", "3"}; std::vector<std::string> entries = {"1", "2", "3"};
MenuOption option; MenuOption option;
auto menu = Menu(&entries, &selected, &option); auto menu = Menu(&entries, &selected, &option);
option.direction = MenuOption::Left; option.direction = Direction::Left;
Screen screen(10, 1); Screen screen(10, 1);
Render(screen, menu->Render()); Render(screen, menu->Render());
EXPECT_EQ(screen.ToString(), EXPECT_EQ(screen.ToString(),

View File

@ -1,26 +1,28 @@
#include <memory> // for __shared_ptr_access #include <ftxui/component/component_options.hpp> // for ResizableSplitOption
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <ftxui/util/ref.hpp> // for Ref
#include <functional> // for function
#include <memory> // for __shared_ptr_access, shared_ptr, allocator
#include <utility> // for move #include <utility> // for move
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
#include "ftxui/component/component.hpp" // for Component, Make, Horizontal, Vertical, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop #include "ftxui/component/component.hpp" // for Horizontal, Make, ResizableSplit, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for Component, ComponentBase
#include "ftxui/component/event.hpp" // for Event #include "ftxui/component/event.hpp" // for Event
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, separator, size, EQUAL, xflex, yflex, hbox, vbox, HEIGHT, WIDTH #include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, size, EQUAL, xflex, yflex, hbox, vbox, HEIGHT, WIDTH, text
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
namespace ftxui { namespace ftxui {
namespace { namespace {
class ResizableSplitLeftBase : public ComponentBase { class ResizableSplitBase : public ComponentBase {
public: public:
ResizableSplitLeftBase(Component main, Component child, int* main_size) ResizableSplitBase(ResizableSplitOption options)
: main_(std::move(main)), : options_(std::move(options)) {
child_(std::move(child)),
main_size_(main_size) {
Add(Container::Horizontal({ Add(Container::Horizontal({
main_, options_->main,
child_, options_->back,
})); }));
} }
@ -45,204 +47,86 @@ class ResizableSplitLeftBase : public ComponentBase {
return true; return true;
} }
if (captured_mouse_) { if (!captured_mouse_) {
*main_size_ = event.mouse().x - box_.x_min;
return true;
}
return ComponentBase::OnEvent(event); return ComponentBase::OnEvent(event);
} }
switch (options_->direction()) {
case Direction::Left:
options_->main_size() = event.mouse().x - box_.x_min;
return true;
case Direction::Right:
options_->main_size() = box_.x_max - event.mouse().x;
return true;
case Direction::Up:
options_->main_size() = event.mouse().y - box_.y_min;
return true;
case Direction::Down:
options_->main_size() = box_.y_max - event.mouse().y;
return true;
}
// NOTREACHED()
return false;
}
Element Render() final { Element Render() final {
switch (options_->direction()) {
case Direction::Left:
return RenderLeft();
case Direction::Right:
return RenderRight();
case Direction::Up:
return RenderTop();
case Direction::Down:
return RenderBottom();
}
// NOTREACHED()
return text("unreacheable");
}
Element RenderLeft() {
return hbox({ return hbox({
main_->Render() | size(WIDTH, EQUAL, *main_size_), options_->main->Render() |
separator() | reflect(separator_box_), size(WIDTH, EQUAL, options_->main_size()),
child_->Render() | xflex, options_->separator_func() | reflect(separator_box_),
options_->back->Render() | xflex,
}) | }) |
reflect(box_); reflect(box_);
}; };
private: Element RenderRight() {
Component main_;
Component child_;
int* const main_size_;
CapturedMouse captured_mouse_;
Box separator_box_;
Box box_;
};
class ResizableSplitRightBase : public ComponentBase {
public:
ResizableSplitRightBase(Component main, Component child, int* main_size)
: main_(std::move(main)),
child_(std::move(child)),
main_size_(main_size) {
Add(Container::Horizontal({
child_,
main_,
}));
}
bool OnEvent(Event event) final {
if (event.is_mouse()) {
return OnMouseEvent(std::move(event));
}
return ComponentBase::OnEvent(std::move(event));
}
bool OnMouseEvent(Event event) {
if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
captured_mouse_.reset();
return true;
}
if (event.mouse().button == Mouse::Left &&
event.mouse().motion == Mouse::Pressed &&
separator_box_.Contain(event.mouse().x, event.mouse().y) &&
!captured_mouse_) {
captured_mouse_ = CaptureMouse(event);
return true;
}
if (captured_mouse_) {
*main_size_ = box_.x_max - event.mouse().x;
return true;
}
return ComponentBase::OnEvent(event);
}
Element Render() final {
return hbox({ return hbox({
child_->Render() | xflex, options_->back->Render() | xflex,
separator() | reflect(separator_box_), options_->separator_func() | reflect(separator_box_),
main_->Render() | size(WIDTH, EQUAL, *main_size_), options_->main->Render() |
size(WIDTH, EQUAL, options_->main_size()),
}) | }) |
reflect(box_); reflect(box_);
}; };
private: Element RenderTop() {
Component main_;
Component child_;
int* const main_size_;
CapturedMouse captured_mouse_;
Box separator_box_;
Box box_;
};
class ResizableSplitTopBase : public ComponentBase {
public:
ResizableSplitTopBase(Component main, Component child, int* main_size)
: main_(std::move(main)),
child_(std::move(child)),
main_size_(main_size) {
Add(Container::Vertical({
main_,
child_,
}));
}
bool OnEvent(Event event) final {
if (event.is_mouse()) {
return OnMouseEvent(std::move(event));
}
return ComponentBase::OnEvent(std::move(event));
}
bool OnMouseEvent(Event event) {
if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
captured_mouse_.reset();
return true;
}
if (event.mouse().button == Mouse::Left &&
event.mouse().motion == Mouse::Pressed &&
separator_box_.Contain(event.mouse().x, event.mouse().y) &&
!captured_mouse_) {
captured_mouse_ = CaptureMouse(event);
return true;
}
if (captured_mouse_) {
*main_size_ = event.mouse().y - box_.y_min;
return true;
}
return ComponentBase::OnEvent(event);
}
Element Render() final {
return vbox({ return vbox({
main_->Render() | size(HEIGHT, EQUAL, *main_size_), options_->main->Render() |
separator() | reflect(separator_box_), size(HEIGHT, EQUAL, options_->main_size()),
child_->Render() | yflex, options_->separator_func() | reflect(separator_box_),
options_->back->Render() | yflex,
}) | }) |
reflect(box_); reflect(box_);
}; };
private: Element RenderBottom() {
Component main_;
Component child_;
int* const main_size_;
CapturedMouse captured_mouse_;
Box separator_box_;
Box box_;
};
class ResizableSplitBottomBase : public ComponentBase {
public:
ResizableSplitBottomBase(Component main, Component child, int* main_size)
: main_(std::move(main)),
child_(std::move(child)),
main_size_(main_size) {
Add(Container::Vertical({
child_,
main_,
}));
}
bool OnEvent(Event event) final {
if (event.is_mouse()) {
return OnMouseEvent(std::move(event));
}
return ComponentBase::OnEvent(std::move(event));
}
bool OnMouseEvent(Event event) {
if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
captured_mouse_.reset();
return true;
}
if (event.mouse().button == Mouse::Left &&
event.mouse().motion == Mouse::Pressed &&
separator_box_.Contain(event.mouse().x, event.mouse().y) &&
!captured_mouse_) {
captured_mouse_ = CaptureMouse(event);
return true;
}
if (captured_mouse_) {
*main_size_ = box_.y_max - event.mouse().y;
return true;
}
return ComponentBase::OnEvent(event);
}
Element Render() final {
return vbox({ return vbox({
child_->Render() | yflex, options_->back->Render() | yflex,
separator() | reflect(separator_box_), options_->separator_func() | reflect(separator_box_),
main_->Render() | size(HEIGHT, EQUAL, *main_size_), options_->main->Render() |
size(HEIGHT, EQUAL, options_->main_size()),
}) | }) |
reflect(box_); reflect(box_);
}; };
private: private:
Component main_; Ref<ResizableSplitOption> options_;
Component child_;
int* const main_size_;
CapturedMouse captured_mouse_; CapturedMouse captured_mouse_;
Box separator_box_; Box separator_box_;
Box box_; Box box_;
@ -250,6 +134,35 @@ class ResizableSplitBottomBase : public ComponentBase {
} // namespace } // namespace
/// @brief A split in between two components.
/// @param options: all the parameters.
///
/// ### Example
///
/// ```cpp
/// auto left = Renderer([] { return text("Left") | center;});
/// auto right = Renderer([] { return text("right") | center;});
/// int left_size = 10;
/// auto component = ResizableSplit({
/// .main = left,
/// .back = right,
/// .direction = Direction::Left,
/// .main_size = &left_size,
/// .separator_func = [] { return separatorDouble(); },
/// });
/// ```
///
/// ### Output
///
/// ```bash
/// ║
/// left ║ right
/// ║
/// ```
Component ResizableSplit(ResizableSplitOption options) {
return Make<ResizableSplitBase>(std::move(options));
}
/// @brief An horizontal split in between two components, configurable using the /// @brief An horizontal split in between two components, configurable using the
/// mouse. /// mouse.
/// @param main The main component of size |main_size|, on the left. /// @param main The main component of size |main_size|, on the left.
@ -276,8 +189,12 @@ class ResizableSplitBottomBase : public ComponentBase {
/// │ /// │
/// ``` /// ```
Component ResizableSplitLeft(Component main, Component back, int* main_size) { Component ResizableSplitLeft(Component main, Component back, int* main_size) {
return Make<ResizableSplitLeftBase>(std::move(main), std::move(back), return ResizableSplit({
main_size); std::move(main),
std::move(back),
Direction::Left,
main_size,
});
} }
/// @brief An horizontal split in between two components, configurable using the /// @brief An horizontal split in between two components, configurable using the
@ -294,7 +211,7 @@ Component ResizableSplitLeft(Component main, Component back, int* main_size) {
/// int right_size = 10; /// int right_size = 10;
/// auto left = Renderer([] { return text("Left") | center;}); /// auto left = Renderer([] { return text("Left") | center;});
/// auto right = Renderer([] { return text("right") | center;}); /// auto right = Renderer([] { return text("right") | center;});
/// auto split = ResizableSplitRight(right, left, &right_size); /// auto split = ResizableSplitRight(right, left, &right_size)
/// screen.Loop(split); /// screen.Loop(split);
/// ``` /// ```
/// ///
@ -306,8 +223,12 @@ Component ResizableSplitLeft(Component main, Component back, int* main_size) {
/// │ /// │
/// ``` /// ```
Component ResizableSplitRight(Component main, Component back, int* main_size) { Component ResizableSplitRight(Component main, Component back, int* main_size) {
return Make<ResizableSplitRightBase>(std::move(main), std::move(back), return ResizableSplit({
main_size); std::move(main),
std::move(back),
Direction::Right,
main_size,
});
} }
/// @brief An vertical split in between two components, configurable using the /// @brief An vertical split in between two components, configurable using the
@ -324,7 +245,7 @@ Component ResizableSplitRight(Component main, Component back, int* main_size) {
/// int top_size = 1; /// int top_size = 1;
/// auto top = Renderer([] { return text("Top") | center;}); /// auto top = Renderer([] { return text("Top") | center;});
/// auto bottom = Renderer([] { return text("Bottom") | center;}); /// auto bottom = Renderer([] { return text("Bottom") | center;});
/// auto split = ResizableSplitTop(top, bottom, &top_size); /// auto split = ResizableSplitTop(top, bottom, &top_size)
/// screen.Loop(split); /// screen.Loop(split);
/// ``` /// ```
/// ///
@ -336,8 +257,12 @@ Component ResizableSplitRight(Component main, Component back, int* main_size) {
/// bottom /// bottom
/// ``` /// ```
Component ResizableSplitTop(Component main, Component back, int* main_size) { Component ResizableSplitTop(Component main, Component back, int* main_size) {
return Make<ResizableSplitTopBase>(std::move(main), std::move(back), return ResizableSplit({
main_size); std::move(main),
std::move(back),
Direction::Up,
main_size,
});
} }
/// @brief An vertical split in between two components, configurable using the /// @brief An vertical split in between two components, configurable using the
@ -354,7 +279,7 @@ Component ResizableSplitTop(Component main, Component back, int* main_size) {
/// int bottom_size = 1; /// int bottom_size = 1;
/// auto top = Renderer([] { return text("Top") | center;}); /// auto top = Renderer([] { return text("Top") | center;});
/// auto bottom = Renderer([] { return text("Bottom") | center;}); /// auto bottom = Renderer([] { return text("Bottom") | center;});
/// auto split = ResizableSplit::Bottom(bottom, top, &bottom_size); /// auto split = ResizableSplit::Bottom(bottom, top, &bottom_size)
/// screen.Loop(split); /// screen.Loop(split);
/// ``` /// ```
/// ///
@ -366,9 +291,14 @@ Component ResizableSplitTop(Component main, Component back, int* main_size) {
/// bottom /// bottom
/// ``` /// ```
Component ResizableSplitBottom(Component main, Component back, int* main_size) { Component ResizableSplitBottom(Component main, Component back, int* main_size) {
return Make<ResizableSplitBottomBase>(std::move(main), std::move(back), return ResizableSplit({
main_size); std::move(main),
std::move(back),
Direction::Down,
main_size,
});
} }
} // namespace ftxui } // namespace ftxui
// Copyright 2021 Arthur Sonzogni. All rights reserved. // Copyright 2021 Arthur Sonzogni. All rights reserved.

View File

@ -1,11 +1,12 @@
#include <gtest/gtest.h> #include <gtest/gtest.h> // for AssertionResult, Message, TestPartResult, Test, EXPECT_EQ, EXPECT_TRUE, TestInfo (ptr only), TEST
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <memory> // for __shared_ptr_access, shared_ptr, allocator #include <memory> // for __shared_ptr_access, shared_ptr, allocator
#include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop #include "ftxui/component/component.hpp" // for ResizableSplit, Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component #include "ftxui/component/component_base.hpp" // for ComponentBase, Component
#include "ftxui/component/event.hpp" // for Event #include "ftxui/component/event.hpp" // for Event
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
#include "ftxui/dom/elements.hpp" // for text, Element #include "ftxui/dom/elements.hpp" // for Element, separatorDouble, text
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
@ -56,6 +57,31 @@ TEST(ResizableSplit, BasicLeft) {
EXPECT_EQ(position, 10); EXPECT_EQ(position, 10);
} }
TEST(ResizableSplit, BasicLeftWithCustomSeparator) {
int position = 1;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Left,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
});
auto screen = Screen(4, 4);
Render(screen, component->Render());
EXPECT_EQ(position, 1);
EXPECT_EQ(screen.ToString(),
"\r\n"
"\r\n"
"\r\n"
"");
EXPECT_TRUE(component->OnEvent(MousePressed(1, 1)));
EXPECT_EQ(position, 1);
EXPECT_TRUE(component->OnEvent(MousePressed(2, 1)));
EXPECT_EQ(position, 2);
EXPECT_TRUE(component->OnEvent(MouseReleased(2, 1)));
EXPECT_EQ(position, 2);
}
TEST(ResizableSplit, BasicRight) { TEST(ResizableSplit, BasicRight) {
int position = 3; int position = 3;
auto component = auto component =
@ -71,6 +97,31 @@ TEST(ResizableSplit, BasicRight) {
EXPECT_EQ(position, 9); EXPECT_EQ(position, 9);
} }
TEST(ResizableSplit, BasicRightWithCustomSeparator) {
int position = 1;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Right,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
});
auto screen = Screen(4, 4);
Render(screen, component->Render());
EXPECT_EQ(position, 1);
EXPECT_EQ(screen.ToString(),
"\r\n"
"\r\n"
"\r\n"
"");
EXPECT_TRUE(component->OnEvent(MousePressed(2, 1)));
EXPECT_EQ(position, 1);
EXPECT_TRUE(component->OnEvent(MousePressed(1, 1)));
EXPECT_EQ(position, 2);
EXPECT_TRUE(component->OnEvent(MouseReleased(1, 1)));
EXPECT_EQ(position, 2);
}
TEST(ResizableSplit, BasicTop) { TEST(ResizableSplit, BasicTop) {
int position = 3; int position = 3;
auto component = auto component =
@ -86,6 +137,31 @@ TEST(ResizableSplit, BasicTop) {
EXPECT_EQ(position, 10); EXPECT_EQ(position, 10);
} }
TEST(ResizableSplit, BasicTopWithCustomSeparator) {
int position = 1;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Up,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
});
auto screen = Screen(4, 4);
Render(screen, component->Render());
EXPECT_EQ(position, 1);
EXPECT_EQ(screen.ToString(),
" \r\n"
"════\r\n"
" \r\n"
" ");
EXPECT_TRUE(component->OnEvent(MousePressed(1, 1)));
EXPECT_EQ(position, 1);
EXPECT_TRUE(component->OnEvent(MousePressed(1, 2)));
EXPECT_EQ(position, 2);
EXPECT_TRUE(component->OnEvent(MouseReleased(1, 2)));
EXPECT_EQ(position, 2);
}
TEST(ResizableSplit, BasicBottom) { TEST(ResizableSplit, BasicBottom) {
int position = 3; int position = 3;
auto component = auto component =
@ -101,6 +177,31 @@ TEST(ResizableSplit, BasicBottom) {
EXPECT_EQ(position, 9); EXPECT_EQ(position, 9);
} }
TEST(ResizableSplit, BasicBottomWithCustomSeparator) {
int position = 1;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Down,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
});
auto screen = Screen(4, 4);
Render(screen, component->Render());
EXPECT_EQ(position, 1);
EXPECT_EQ(screen.ToString(),
" \r\n"
" \r\n"
"════\r\n"
" ");
EXPECT_TRUE(component->OnEvent(MousePressed(1, 2)));
EXPECT_EQ(position, 1);
EXPECT_TRUE(component->OnEvent(MousePressed(1, 1)));
EXPECT_EQ(position, 2);
EXPECT_TRUE(component->OnEvent(MouseReleased(1, 1)));
EXPECT_EQ(position, 2);
}
} // namespace ftxui } // namespace ftxui
// Copyright 2022 Arthur Sonzogni. All rights reserved. // Copyright 2022 Arthur Sonzogni. All rights reserved.

View File

@ -1,5 +1,6 @@
#include <algorithm> // for max, min #include <algorithm> // for max, min
#include <ftxui/component/component_options.hpp> // for SliderOption #include <ftxui/component/component_options.hpp> // for SliderOption
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <string> // for allocator #include <string> // for allocator
#include <utility> // for move #include <utility> // for move
@ -9,7 +10,7 @@
#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp #include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
#include "ftxui/component/screen_interactive.hpp" // for Component #include "ftxui/component/screen_interactive.hpp" // for Component
#include "ftxui/dom/elements.hpp" // for operator|, text, GaugeDirection, Element, xflex, hbox, color, underlined, GaugeDirection::Down, GaugeDirection::Left, GaugeDirection::Right, GaugeDirection::Up, reflect, Decorator, dim, vcenter, yflex, gaugeDirection #include "ftxui/dom/elements.hpp" // for operator|, text, Element, xflex, hbox, color, underlined, reflect, Decorator, dim, vcenter, focus, nothing, select, yflex, gaugeDirection
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White #include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White
#include "ftxui/screen/util.hpp" // for clamp #include "ftxui/screen/util.hpp" // for clamp
@ -18,13 +19,13 @@
namespace ftxui { namespace ftxui {
namespace { namespace {
Decorator flexDirection(GaugeDirection direction) { Decorator flexDirection(Direction direction) {
switch (direction) { switch (direction) {
case GaugeDirection::Up: case Direction::Up:
case GaugeDirection::Down: case Direction::Down:
return yflex; return yflex;
case GaugeDirection::Left: case Direction::Left:
case GaugeDirection::Right: case Direction::Right:
return xflex; return xflex;
} }
return xflex; // NOT_REACHED() return xflex; // NOT_REACHED()
@ -52,56 +53,56 @@ class SliderBase : public ComponentBase {
void OnLeft() { void OnLeft() {
switch (options_->direction) { switch (options_->direction) {
case GaugeDirection::Right: case Direction::Right:
value_() -= increment_(); value_() -= increment_();
break; break;
case GaugeDirection::Left: case Direction::Left:
value_() += increment_(); value_() += increment_();
break; break;
case GaugeDirection::Up: case Direction::Up:
case GaugeDirection::Down: case Direction::Down:
break; break;
} }
} }
void OnRight() { void OnRight() {
switch (options_->direction) { switch (options_->direction) {
case GaugeDirection::Right: case Direction::Right:
value_() += increment_(); value_() += increment_();
break; break;
case GaugeDirection::Left: case Direction::Left:
value_() -= increment_(); value_() -= increment_();
break; break;
case GaugeDirection::Up: case Direction::Up:
case GaugeDirection::Down: case Direction::Down:
break; break;
} }
} }
void OnUp() { void OnUp() {
switch (options_->direction) { switch (options_->direction) {
case GaugeDirection::Up: case Direction::Up:
value_() -= increment_(); value_() -= increment_();
break; break;
case GaugeDirection::Down: case Direction::Down:
value_() += increment_(); value_() += increment_();
break; break;
case GaugeDirection::Left: case Direction::Left:
case GaugeDirection::Right: case Direction::Right:
break; break;
} }
} }
void OnDown() { void OnDown() {
switch (options_->direction) { switch (options_->direction) {
case GaugeDirection::Down: case Direction::Down:
value_() -= increment_(); value_() -= increment_();
break; break;
case GaugeDirection::Up: case Direction::Up:
value_() += increment_(); value_() += increment_();
break; break;
case GaugeDirection::Left: case Direction::Left:
case GaugeDirection::Right: case Direction::Right:
break; break;
} }
} }
@ -153,25 +154,25 @@ class SliderBase : public ComponentBase {
if (captured_mouse_) { if (captured_mouse_) {
switch (options_->direction) { switch (options_->direction) {
case GaugeDirection::Right: { case Direction::Right: {
value_() = min_() + (event.mouse().x - gauge_box_.x_min) * value_() = min_() + (event.mouse().x - gauge_box_.x_min) *
(max_() - min_()) / (max_() - min_()) /
(gauge_box_.x_max - gauge_box_.x_min); (gauge_box_.x_max - gauge_box_.x_min);
break; break;
} }
case GaugeDirection::Left: { case Direction::Left: {
value_() = max_() - (event.mouse().x - gauge_box_.x_min) * value_() = max_() - (event.mouse().x - gauge_box_.x_min) *
(max_() - min_()) / (max_() - min_()) /
(gauge_box_.x_max - gauge_box_.x_min); (gauge_box_.x_max - gauge_box_.x_min);
break; break;
} }
case GaugeDirection::Down: { case Direction::Down: {
value_() = min_() + (event.mouse().y - gauge_box_.y_min) * value_() = min_() + (event.mouse().y - gauge_box_.y_min) *
(max_() - min_()) / (max_() - min_()) /
(gauge_box_.y_max - gauge_box_.y_min); (gauge_box_.y_max - gauge_box_.y_min);
break; break;
} }
case GaugeDirection::Up: { case Direction::Up: {
value_() = max_() - (event.mouse().y - gauge_box_.y_min) * value_() = max_() - (event.mouse().y - gauge_box_.y_min) *
(max_() - min_()) / (max_() - min_()) /
(gauge_box_.y_max - gauge_box_.y_min); (gauge_box_.y_max - gauge_box_.y_min);

View File

@ -2,7 +2,8 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <array> // for array #include <array> // for array
#include <ftxui/component/mouse.hpp> // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released #include <ftxui/component/mouse.hpp> // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
#include <ftxui/dom/elements.hpp> // for GaugeDirection, GaugeDirection::Down, GaugeDirection::Left, GaugeDirection::Right, GaugeDirection::Up, frame #include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <ftxui/dom/elements.hpp> // for frame
#include <memory> // for shared_ptr, __shared_ptr_access, allocator #include <memory> // for shared_ptr, __shared_ptr_access, allocator
#include <string> // for to_string #include <string> // for to_string
@ -47,7 +48,7 @@ TEST(SliderTest, Right) {
.min = 0, .min = 0,
.max = 100, .max = 100,
.increment = 10, .increment = 10,
.direction = GaugeDirection::Right, .direction = Direction::Right,
}); });
Screen screen(11, 1); Screen screen(11, 1);
Render(screen, slider->Render()); Render(screen, slider->Render());
@ -70,7 +71,7 @@ TEST(SliderTest, Left) {
.min = 0, .min = 0,
.max = 100, .max = 100,
.increment = 10, .increment = 10,
.direction = GaugeDirection::Left, .direction = Direction::Left,
}); });
Screen screen(11, 1); Screen screen(11, 1);
Render(screen, slider->Render()); Render(screen, slider->Render());
@ -93,7 +94,7 @@ TEST(SliderTest, Down) {
.min = 0, .min = 0,
.max = 100, .max = 100,
.increment = 10, .increment = 10,
.direction = GaugeDirection::Down, .direction = Direction::Down,
}); });
Screen screen(1, 11); Screen screen(1, 11);
Render(screen, slider->Render()); Render(screen, slider->Render());
@ -116,7 +117,7 @@ TEST(SliderTest, Up) {
.min = 0, .min = 0,
.max = 100, .max = 100,
.increment = 10, .increment = 10,
.direction = GaugeDirection::Up, .direction = Direction::Up,
}); });
Screen screen(1, 11); Screen screen(1, 11);
Render(screen, slider->Render()); Render(screen, slider->Render());

View File

@ -1,7 +1,8 @@
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <memory> // for allocator, make_shared #include <memory> // for allocator, make_shared
#include <string> // for string #include <string> // for string
#include "ftxui/dom/elements.hpp" // for GaugeDirection, Element, GaugeDirection::Down, GaugeDirection::Left, GaugeDirection::Right, GaugeDirection::Up, gauge, gaugeDirection, gaugeDown, gaugeLeft, gaugeRight, gaugeUp #include "ftxui/dom/elements.hpp" // for Element, gauge, gaugeDirection, gaugeDown, gaugeLeft, gaugeRight, gaugeUp
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
@ -40,7 +41,7 @@ static const std::string charset_vertical[10] = {
class Gauge : public Node { class Gauge : public Node {
public: public:
Gauge(float progress, GaugeDirection direction) Gauge(float progress, Direction direction)
: progress_(progress), direction_(direction) { : progress_(progress), direction_(direction) {
// This handle NAN correctly: // This handle NAN correctly:
if (!(progress_ > 0.F)) { if (!(progress_ > 0.F)) {
@ -53,15 +54,15 @@ class Gauge : public Node {
void ComputeRequirement() override { void ComputeRequirement() override {
switch (direction_) { switch (direction_) {
case GaugeDirection::Right: case Direction::Right:
case GaugeDirection::Left: case Direction::Left:
requirement_.flex_grow_x = 1; requirement_.flex_grow_x = 1;
requirement_.flex_grow_y = 0; requirement_.flex_grow_y = 0;
requirement_.flex_shrink_x = 1; requirement_.flex_shrink_x = 1;
requirement_.flex_shrink_y = 0; requirement_.flex_shrink_y = 0;
break; break;
case GaugeDirection::Up: case Direction::Up:
case GaugeDirection::Down: case Direction::Down:
requirement_.flex_grow_x = 0; requirement_.flex_grow_x = 0;
requirement_.flex_grow_y = 1; requirement_.flex_grow_y = 1;
requirement_.flex_shrink_x = 0; requirement_.flex_shrink_x = 0;
@ -74,16 +75,16 @@ class Gauge : public Node {
void Render(Screen& screen) override { void Render(Screen& screen) override {
switch (direction_) { switch (direction_) {
case GaugeDirection::Right: case Direction::Right:
RenderHorizontal(screen, /*invert=*/false); RenderHorizontal(screen, /*invert=*/false);
break; break;
case GaugeDirection::Up: case Direction::Up:
RenderVertical(screen, /*invert=*/false); RenderVertical(screen, /*invert=*/false);
break; break;
case GaugeDirection::Left: case Direction::Left:
RenderHorizontal(screen, /*invert=*/true); RenderHorizontal(screen, /*invert=*/true);
break; break;
case GaugeDirection::Down: case Direction::Down:
RenderVertical(screen, /*invert=*/true); RenderVertical(screen, /*invert=*/true);
break; break;
} }
@ -151,7 +152,7 @@ class Gauge : public Node {
private: private:
float progress_; float progress_;
GaugeDirection direction_; Direction direction_;
}; };
/// @brief Draw a high definition progress bar progressing in specified /// @brief Draw a high definition progress bar progressing in specified
@ -159,7 +160,7 @@ class Gauge : public Node {
/// @param progress The proportion of the area to be filled. Belong to [0,1]. /// @param progress The proportion of the area to be filled. Belong to [0,1].
// @param direction Direction of progress bars progression. // @param direction Direction of progress bars progression.
/// @ingroup dom /// @ingroup dom
Element gaugeDirection(float progress, GaugeDirection direction) { Element gaugeDirection(float progress, Direction direction) {
return std::make_shared<Gauge>(progress, direction); return std::make_shared<Gauge>(progress, direction);
} }
@ -182,7 +183,7 @@ Element gaugeDirection(float progress, GaugeDirection direction) {
/// └──────────────────────────────────────────────────────────────────────────┘ /// └──────────────────────────────────────────────────────────────────────────┘
/// ~~~ /// ~~~
Element gaugeRight(float progress) { Element gaugeRight(float progress) {
return gaugeDirection(progress, GaugeDirection::Right); return gaugeDirection(progress, Direction::Right);
} }
/// @brief Draw a high definition progress bar progressing from right to left. /// @brief Draw a high definition progress bar progressing from right to left.
@ -204,7 +205,7 @@ Element gaugeRight(float progress) {
/// └──────────────────────────────────────────────────────────────────────────┘ /// └──────────────────────────────────────────────────────────────────────────┘
/// ~~~ /// ~~~
Element gaugeLeft(float progress) { Element gaugeLeft(float progress) {
return gaugeDirection(progress, GaugeDirection::Left); return gaugeDirection(progress, Direction::Left);
} }
/// @brief Draw a high definition progress bar progressing from bottom to top. /// @brief Draw a high definition progress bar progressing from bottom to top.
@ -233,7 +234,7 @@ Element gaugeLeft(float progress) {
/// └─┘ /// └─┘
/// ~~~ /// ~~~
Element gaugeUp(float progress) { Element gaugeUp(float progress) {
return gaugeDirection(progress, GaugeDirection::Up); return gaugeDirection(progress, Direction::Up);
} }
/// @brief Draw a high definition progress bar progressing from top to bottom. /// @brief Draw a high definition progress bar progressing from top to bottom.
@ -262,7 +263,7 @@ Element gaugeUp(float progress) {
/// └─┘ /// └─┘
/// ~~~ /// ~~~
Element gaugeDown(float progress) { Element gaugeDown(float progress) {
return gaugeDirection(progress, GaugeDirection::Down); return gaugeDirection(progress, Direction::Down);
} }
/// @brief Draw a high definition progress bar. /// @brief Draw a high definition progress bar.

View File

@ -3,7 +3,7 @@
#include <utility> // for move #include <utility> // for move
#include <vector> // for __alloc_traits<>::value_type #include <vector> // for __alloc_traits<>::value_type
#include "ftxui/dom/elements.hpp" // for Constraint, Direction, EQUAL, GREATER_THAN, LESS_THAN, WIDTH, unpack, Decorator, Element, size #include "ftxui/dom/elements.hpp" // for Constraint, WidthOrHeight, EQUAL, GREATER_THAN, LESS_THAN, WIDTH, unpack, Decorator, Element, size
#include "ftxui/dom/node.hpp" // for Node, Elements #include "ftxui/dom/node.hpp" // for Node, Elements
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
@ -12,7 +12,7 @@ namespace ftxui {
class Size : public Node { class Size : public Node {
public: public:
Size(Element child, Direction direction, Constraint constraint, int value) Size(Element child, WidthOrHeight direction, Constraint constraint, int value)
: Node(unpack(std::move(child))), : Node(unpack(std::move(child))),
direction_(direction), direction_(direction),
constraint_(constraint), constraint_(constraint),
@ -71,7 +71,7 @@ class Size : public Node {
} }
private: private:
Direction direction_; WidthOrHeight direction_;
Constraint constraint_; Constraint constraint_;
int value_; int value_;
}; };
@ -82,7 +82,7 @@ class Size : public Node {
/// @param constraint The type of constaint. /// @param constraint The type of constaint.
/// @param value The value. /// @param value The value.
/// @ingroup dom /// @ingroup dom
Decorator size(Direction direction, Constraint constraint, int value) { Decorator size(WidthOrHeight direction, Constraint constraint, int value) {
return [=](Element e) { return [=](Element e) {
return std::make_shared<Size>(std::move(e), direction, constraint, value); return std::make_shared<Size>(std::move(e), direction, constraint, value);
}; };