mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-22 18:59:59 +08:00
Add "frame" : scrollable area.
This commit is contained in:
parent
cb4df0b56f
commit
fddcbdea65
@ -14,11 +14,11 @@ A C++ library for making text based user interface.
|
||||
~~~cpp
|
||||
vbox(
|
||||
hbox(
|
||||
text(L"left") | frame,
|
||||
text(L"middle") | frame | flex,
|
||||
text(L"right") | frame
|
||||
text(L"left") | border,
|
||||
text(L"middle") | border | flex,
|
||||
text(L"right") | border
|
||||
),
|
||||
gauge(0.5) | frame
|
||||
gauge(0.5) | border
|
||||
)
|
||||
~~~
|
||||
|
||||
|
@ -5,12 +5,14 @@ function(example name)
|
||||
endfunction(example)
|
||||
|
||||
example(checkbox)
|
||||
example(checkbox_in_frame)
|
||||
example(gallery)
|
||||
example(input)
|
||||
example(menu)
|
||||
example(menu2)
|
||||
example(menu_style)
|
||||
example(radiobox)
|
||||
example(radiobox_in_frame)
|
||||
example(tab_horizontal)
|
||||
example(tab_vertical)
|
||||
example(toggle)
|
||||
|
@ -22,19 +22,10 @@ class MyComponent : public Component {
|
||||
box_3_.label = L"Use WebAssembly";
|
||||
box_3_.state = true;
|
||||
}
|
||||
|
||||
Element Render() {
|
||||
return
|
||||
window(text(L" Checkbox "),
|
||||
hbox(
|
||||
container_.Render()
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
auto screen = ScreenInteractive::FixedSize(30,5);
|
||||
auto screen = ScreenInteractive::TerminalOutput();
|
||||
MyComponent component;
|
||||
screen.Loop(&component);
|
||||
return 0;
|
||||
|
42
examples/component/checkbox_in_frame.cpp
Normal file
42
examples/component/checkbox_in_frame.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "ftxui/component/checkbox.hpp"
|
||||
#include "ftxui/component/container.hpp"
|
||||
#include "ftxui/component/input.hpp"
|
||||
#include "ftxui/component/menu.hpp"
|
||||
#include "ftxui/component/checkbox.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/component/toggle.hpp"
|
||||
#include "ftxui/screen/string.hpp"
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
class MyComponent : public Component {
|
||||
public:
|
||||
MyComponent() {
|
||||
Add(&container);
|
||||
checkbox.resize(30);
|
||||
for(int i = 0; i<checkbox.size(); ++i) {
|
||||
checkbox[i].label = (L"CheckBox " + to_wstring(i));
|
||||
container.Add(&checkbox[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Element Render() override {
|
||||
Elements content;
|
||||
for(auto& it : checkbox) {
|
||||
content.push_back(it.Render());
|
||||
}
|
||||
return vbox(std::move(content)) | frame | size(20, 10) | border;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<CheckBox> checkbox;
|
||||
Container container = Container::Vertical();
|
||||
};
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
auto screen = ScreenInteractive::FitComponent();
|
||||
MyComponent component;
|
||||
screen.Loop(&component);
|
||||
|
||||
return 0;
|
||||
}
|
@ -69,7 +69,7 @@ class MyComponent : public Component {
|
||||
Render(L"radiobox", radiobox),
|
||||
separator(),
|
||||
Render(L"input", input)
|
||||
) | frame;
|
||||
) | border | frame | size(10,10) | border;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -30,7 +30,7 @@ class MyComponent : public Component {
|
||||
|
||||
Element Render() override {
|
||||
return
|
||||
frame(
|
||||
border(
|
||||
vbox(
|
||||
hbox(text(L" input_1 : "), input_1.Render()),
|
||||
hbox(text(L" input_2 : "), input_2.Render()),
|
||||
|
@ -34,7 +34,7 @@ class MyComponent : public Component {
|
||||
Element Render() override {
|
||||
int sum = left_menu.selected * 10 + right_menu.selected;
|
||||
return
|
||||
frame(
|
||||
border(
|
||||
vbox(
|
||||
// -------- Top panel --------------
|
||||
hbox(
|
||||
|
@ -26,21 +26,21 @@ class MyComponent : public Component {
|
||||
}
|
||||
|
||||
menu_2.selected_style = color(Color::Blue);
|
||||
menu_2.active_style = bold | color(Color::Blue);
|
||||
menu_2.focused_style = bold | color(Color::Blue);
|
||||
|
||||
menu_3.selected_style = color(Color::Blue);
|
||||
menu_3.active_style = bgcolor(Color::Blue);
|
||||
menu_3.focused_style = bgcolor(Color::Blue);
|
||||
|
||||
menu_4.selected_style = bgcolor(Color::Blue);
|
||||
menu_4.active_style = bgcolor(Color::BlueLight);
|
||||
menu_4.focused_style = bgcolor(Color::BlueLight);
|
||||
|
||||
menu_5.normal_style = bgcolor(Color::Blue);
|
||||
menu_5.selected_style = bgcolor(Color::Yellow);
|
||||
menu_5.active_style = bgcolor(Color::Red);
|
||||
menu_5.focused_style = bgcolor(Color::Red);
|
||||
|
||||
menu_6.normal_style = dim | color(Color::Blue);
|
||||
menu_6.selected_style = color(Color::Blue);
|
||||
menu_6.active_style = bold | color(Color::Blue);
|
||||
menu_6.focused_style = bold | color(Color::Blue);
|
||||
}
|
||||
|
||||
std::function<void()> on_enter = [](){};
|
||||
@ -62,7 +62,7 @@ class MyComponent : public Component {
|
||||
menu_4.Render() | flex, separator(),
|
||||
menu_5.Render() | flex, separator(),
|
||||
menu_6.Render() | flex
|
||||
) | frame;
|
||||
) | border;
|
||||
}
|
||||
};
|
||||
|
||||
|
34
examples/component/radiobox_in_frame.cpp
Normal file
34
examples/component/radiobox_in_frame.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "ftxui/component/checkbox.hpp"
|
||||
#include "ftxui/component/container.hpp"
|
||||
#include "ftxui/component/input.hpp"
|
||||
#include "ftxui/component/menu.hpp"
|
||||
#include "ftxui/component/radiobox.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/component/toggle.hpp"
|
||||
#include "ftxui/screen/string.hpp"
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
class MyComponent : public Component {
|
||||
RadioBox radiobox;
|
||||
|
||||
public:
|
||||
MyComponent() {
|
||||
for(int i = 0; i<30; ++i) {
|
||||
radiobox.entries.push_back(L"RadioBox " + to_wstring(i));
|
||||
}
|
||||
Add(&radiobox);
|
||||
}
|
||||
|
||||
Element Render() override {
|
||||
return radiobox.Render() | frame | size(20,10) | border;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
auto screen = ScreenInteractive::FitComponent();
|
||||
MyComponent component;
|
||||
screen.Loop(&component);
|
||||
|
||||
return 0;
|
||||
}
|
@ -50,7 +50,7 @@ class MyComponent : public Component {
|
||||
toggle_.Render(),
|
||||
separator(),
|
||||
tab_container_.Render()
|
||||
) | frame;
|
||||
) | border;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -4,7 +4,7 @@ function(example name)
|
||||
endfunction(example)
|
||||
|
||||
example(dbox)
|
||||
example(frame)
|
||||
example(border)
|
||||
example(gauge)
|
||||
example(package_manager)
|
||||
example(separator)
|
||||
|
@ -15,13 +15,11 @@ int main(int argc, const char *argv[])
|
||||
text(L"Line 1"),
|
||||
text(L"Line 2"),
|
||||
text(L"Line 3"),
|
||||
frame(
|
||||
vbox(
|
||||
text(L"Line 4"),
|
||||
text(L"Line 5"),
|
||||
text(L"Line 6")
|
||||
)
|
||||
),
|
||||
) | border,
|
||||
hbox(
|
||||
window(text(L"frame 2"),
|
||||
vbox(
|
@ -7,20 +7,14 @@ int main(int argc, const char *argv[])
|
||||
using namespace ftxui;
|
||||
auto document =
|
||||
dbox(
|
||||
frame(
|
||||
vbox(
|
||||
text(L"line_1"),
|
||||
text(L"line_2"),
|
||||
text(L"line_3"),
|
||||
text(L"line_4"),
|
||||
text(L"line_5")
|
||||
)
|
||||
),
|
||||
center(
|
||||
frame(
|
||||
text(L"overlay")
|
||||
)
|
||||
)
|
||||
) | border,
|
||||
text(L"overlay") | border | center
|
||||
);
|
||||
auto screen = Screen::TerminalOutput(document);
|
||||
Render(screen, document.get());
|
||||
|
@ -24,7 +24,7 @@ int main(int argc, const char *argv[])
|
||||
)
|
||||
);
|
||||
}
|
||||
auto document = hbox(vbox(std::move(entries)) | frame, filler());
|
||||
auto document = hbox(vbox(std::move(entries)) | border, filler());
|
||||
auto screen = Screen::TerminalOutput(document);
|
||||
Render(screen, document.get());
|
||||
std::cout << reset_position << screen.ToString() << std::flush;
|
||||
|
@ -1,14 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
add_library(screen
|
||||
src/ftxui/screen/box.cpp
|
||||
src/ftxui/screen/screen.cpp
|
||||
src/ftxui/screen/terminal.cpp
|
||||
src/ftxui/screen/string.cpp
|
||||
src/ftxui/screen/terminal.cpp
|
||||
)
|
||||
|
||||
add_library(dom
|
||||
src/ftxui/dom/blink.cpp
|
||||
src/ftxui/dom/bold.cpp
|
||||
src/ftxui/dom/border.cpp
|
||||
src/ftxui/dom/color.cpp
|
||||
src/ftxui/dom/composite_decorator.cpp
|
||||
src/ftxui/dom/dbox.cpp
|
||||
|
@ -13,7 +13,7 @@ class Container : public Component {
|
||||
public:
|
||||
static Container Vertical();
|
||||
static Container Horizontal();
|
||||
static Container Tab(size_t* selector);
|
||||
static Container Tab(int* selector);
|
||||
|
||||
~Container() override = default;
|
||||
|
||||
@ -36,8 +36,8 @@ class Container : public Component {
|
||||
Element TabRender();
|
||||
RenderHandler render_handler_;
|
||||
|
||||
size_t selected_ = 0;
|
||||
size_t* selector_ = &selected_;
|
||||
int selected_ = 0;
|
||||
int* selector_ = &selected_;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
@ -15,9 +15,9 @@ class Menu : public Component {
|
||||
|
||||
// State.
|
||||
std::vector<std::wstring> entries = {};
|
||||
size_t selected = 0;
|
||||
int selected = 0;
|
||||
|
||||
Decorator active_style = inverted;
|
||||
Decorator focused_style = inverted;
|
||||
Decorator selected_style = bold;
|
||||
Decorator normal_style = nothing;
|
||||
|
||||
|
@ -13,9 +13,13 @@ class Toggle : public Component {
|
||||
~Toggle() override = default;
|
||||
|
||||
// State.
|
||||
size_t selected = 0;
|
||||
int selected = 0;
|
||||
std::vector<std::wstring> entries = {L"On", L"Off"};
|
||||
|
||||
Decorator focused_style = inverted;
|
||||
Decorator selected_style = bold;
|
||||
Decorator normal_style = dim;
|
||||
|
||||
// Callback.
|
||||
std::function<void()> on_change = [](){};
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
#ifndef FTXUI_DOM_BOX_HPP
|
||||
#define FTXUI_DOM_BOX_HPP
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
struct Box {
|
||||
int left;
|
||||
int right;
|
||||
int top;
|
||||
int bottom;
|
||||
};
|
||||
|
||||
}; // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_DOM_BOX_HPP */
|
@ -12,21 +12,11 @@ using Element = std::unique_ptr<Node>;
|
||||
using Elements = std::vector<Element>;
|
||||
using Decorator = std::function<Element(Element)>;
|
||||
|
||||
// --- Layout ----
|
||||
Element vbox(Elements);
|
||||
Element hbox(Elements);
|
||||
Element dbox(Elements);
|
||||
|
||||
// -- Flexibility --
|
||||
Element filler();
|
||||
Element flex(Element);
|
||||
Decorator size(size_t width, size_t height);
|
||||
|
||||
// --- Widget --
|
||||
// --- Widget ---
|
||||
Element text(std::wstring text);
|
||||
Element separator();
|
||||
Element gauge(float ratio);
|
||||
Element frame(Element);
|
||||
Element border(Element);
|
||||
Element window(Element title, Element content);
|
||||
Element spinner(int charset_index, size_t image_index);
|
||||
|
||||
@ -36,19 +26,37 @@ Element dim(Element);
|
||||
Element inverted(Element);
|
||||
Element underlined(Element);
|
||||
Element blink(Element);
|
||||
|
||||
Decorator color(Color);
|
||||
Decorator bgcolor(Color);
|
||||
Element color(Color, Element);
|
||||
Element bgcolor(Color, Element);
|
||||
|
||||
// --- Util ---
|
||||
// --- Layout ---
|
||||
// Horizontal, Vertical or stacked set of elements.
|
||||
Element vbox(Elements);
|
||||
Element hbox(Elements);
|
||||
Element dbox(Elements);
|
||||
|
||||
// -- Flexibility ---
|
||||
// Define how to share the remaining space when not all of it is used inside a
|
||||
// container.
|
||||
Element filler();
|
||||
Element flex(Element);
|
||||
Decorator size(size_t width, size_t height);
|
||||
|
||||
// --- 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 focus(Element);
|
||||
Element select(Element);
|
||||
|
||||
// --- Util --------------------------------------------------------------------
|
||||
Element hcenter(Element);
|
||||
Element vcenter(Element);
|
||||
Element center(Element);
|
||||
Element align_right(Element);
|
||||
|
||||
// --- Util ---
|
||||
Element nothing(Element element);
|
||||
|
||||
// Pipe elements into decorator togethers.
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "ftxui/dom/box.hpp"
|
||||
#include "ftxui/dom/requirement.hpp"
|
||||
#include "ftxui/screen/box.hpp"
|
||||
#include "ftxui/screen/screen.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef FTXUI_DOM_REQUIREMENT_HPP
|
||||
#define FTXUI_DOM_REQUIREMENT_HPP
|
||||
|
||||
#include "ftxui/screen/box.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
struct Requirement {
|
||||
@ -9,6 +11,14 @@ struct Requirement {
|
||||
|
||||
// How much flexibility is given to the component.
|
||||
struct { int x = 0; int y = 0; } flex;
|
||||
|
||||
// Frame.
|
||||
enum Selection {
|
||||
NORMAL = 0,
|
||||
SELECTED = 1,
|
||||
FOCUSED = 2,
|
||||
} selection = NORMAL;
|
||||
Box selected_box;
|
||||
};
|
||||
|
||||
}; // namespace ftxui
|
||||
|
17
ftxui/include/ftxui/screen/box.hpp
Normal file
17
ftxui/include/ftxui/screen/box.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef FTXUI_SCREEN_BOX_HPP
|
||||
#define FTXUI_SCREEN_BOX_HPP
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
struct Box {
|
||||
int x_min;
|
||||
int x_max;
|
||||
int y_min;
|
||||
int y_max;
|
||||
|
||||
static Box Intersection(Box a, Box b);
|
||||
};
|
||||
|
||||
}; // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_SCREEN_BOX_HPP */
|
@ -6,6 +6,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "ftxui/screen/color.hpp"
|
||||
#include "ftxui/screen/box.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
class Node;
|
||||
@ -51,6 +52,7 @@ class Screen {
|
||||
void Clear();
|
||||
|
||||
void ApplyShader();
|
||||
Box stencil;
|
||||
|
||||
protected:
|
||||
size_t dimx_;
|
||||
|
22
ftxui/include/ftxui/util/autoreset.hpp
Normal file
22
ftxui/include/ftxui/util/autoreset.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef FTXUI_UTIL_AUTORESET_HPP
|
||||
#define FTXUI_UTIL_AUTORESET_HPP
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
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 */
|
@ -4,8 +4,11 @@
|
||||
namespace ftxui {
|
||||
|
||||
Element CheckBox::Render() {
|
||||
auto style = Focused() ? focused_style : unfocused_style;
|
||||
return hbox(text(state ? checked : unchecked), text(label) | style);
|
||||
bool is_focused = Focused();
|
||||
auto style = is_focused ? focused_style : unfocused_style;
|
||||
auto focus_management = is_focused ? focus : state ? select : nothing;
|
||||
return hbox(text(state ? checked : unchecked),
|
||||
text(label) | style | focus_management);
|
||||
}
|
||||
|
||||
bool CheckBox::OnEvent(Event event) {
|
||||
|
@ -19,7 +19,7 @@ Container Container::Vertical() {
|
||||
}
|
||||
|
||||
// static
|
||||
Container Container::Tab(size_t* selector) {
|
||||
Container Container::Tab(int* selector) {
|
||||
Container container;
|
||||
container.event_handler_ = &Container::TabEvent;
|
||||
container.render_handler_ = &Container::TabRender;
|
||||
@ -53,7 +53,7 @@ bool Container::VerticalEvent(Event event) {
|
||||
|
||||
// Left pressed ?
|
||||
if (event == Event::ArrowDown || event == Event::Character('j')) {
|
||||
if (selected_ != children_.size() - 1) {
|
||||
if (selected_ != int(children_.size()) - 1) {
|
||||
selected_++;
|
||||
return true;
|
||||
}
|
||||
@ -74,7 +74,7 @@ bool Container::HorizontalEvent(Event event) {
|
||||
|
||||
// Left pressed ?
|
||||
if (event == Event::ArrowRight || event == Event::Character('l')) {
|
||||
if (selected_ != children_.size() - 1) {
|
||||
if (selected_ != int(children_.size()) - 1) {
|
||||
selected_++;
|
||||
return true;
|
||||
}
|
||||
|
@ -26,12 +26,15 @@ Element Input::Render() {
|
||||
std::wstring part_after_cursor = cursor_position < (int)content.size() - 1
|
||||
? content.substr(cursor_position + 1)
|
||||
: L"";
|
||||
auto focused =
|
||||
is_focused ? focus : select;
|
||||
|
||||
return
|
||||
hbox(
|
||||
text(part_before_cursor),
|
||||
text(part_at_cursor) | underlined,
|
||||
text(part_at_cursor) | underlined | focused,
|
||||
text(part_after_cursor)
|
||||
) | flex | inverted;
|
||||
) | flex | inverted | frame;
|
||||
}
|
||||
bool Input::OnEvent(Event event) {
|
||||
std::wstring c;
|
||||
|
@ -6,17 +6,14 @@ namespace ftxui {
|
||||
|
||||
Element Menu::Render() {
|
||||
std::vector<Element> elements;
|
||||
bool focused = Focused();
|
||||
bool is_focused = Focused();
|
||||
for (size_t i = 0; i < entries.size(); ++i) {
|
||||
if (selected == i) {
|
||||
if (focused)
|
||||
elements.push_back(active_style(text(L"> " + entries[i])));
|
||||
else
|
||||
elements.push_back(selected_style(text(L"> " + entries[i])));
|
||||
}
|
||||
else {
|
||||
elements.push_back(normal_style(text(L" " + entries[i])));
|
||||
}
|
||||
auto style = (selected != int(i))
|
||||
? normal_style
|
||||
: is_focused ? focused_style : selected_style;
|
||||
auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select;
|
||||
auto icon = (selected != int(i)) ? L" " : L"> ";
|
||||
elements.push_back(text(icon + entries[i]) | style | focused);
|
||||
}
|
||||
return vbox(std::move(elements));
|
||||
}
|
||||
@ -25,12 +22,12 @@ bool Menu::OnEvent(Event event) {
|
||||
if (!Focused())
|
||||
return false;
|
||||
|
||||
size_t new_selected = selected;
|
||||
int new_selected = selected;
|
||||
if (event == Event::ArrowUp || event == Event::Character('k'))
|
||||
new_selected--;
|
||||
if (event == Event::ArrowDown || event == Event::Character('j'))
|
||||
new_selected++;
|
||||
new_selected = std::max(size_t(0), std::min(entries.size()-size_t(1), new_selected));
|
||||
new_selected = std::max(0, std::min(int(entries.size()) - 1, new_selected));
|
||||
|
||||
if (selected != new_selected) {
|
||||
selected = new_selected;
|
||||
|
@ -9,8 +9,12 @@ Element RadioBox::Render() {
|
||||
for (size_t i = 0; i < entries.size(); ++i) {
|
||||
auto style =
|
||||
(focused == int(i) && is_focused) ? focused_style : unfocused_style;
|
||||
auto focus_management =
|
||||
(focused != int(i)) ? nothing : is_focused ? focus : select;
|
||||
|
||||
const std::wstring& symbol = selected == int(i) ? checked : unchecked;
|
||||
elements.push_back(hbox(text(symbol), text(entries[i]) | style));
|
||||
elements.push_back(hbox(text(symbol), text(entries[i]) | style) |
|
||||
focus_management);
|
||||
}
|
||||
return vbox(std::move(elements));
|
||||
}
|
||||
@ -30,7 +34,7 @@ bool RadioBox::OnEvent(Event event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event == Event::Character(' ')) {
|
||||
if (event == Event::Character(' ') || event==Event::Return) {
|
||||
selected = focused;
|
||||
on_change();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace ftxui {
|
||||
|
||||
Element Toggle::Render() {
|
||||
auto highlight = Focused() ? inverted : bold;
|
||||
bool is_focused = Focused();
|
||||
|
||||
Elements children;
|
||||
for(size_t i = 0; i<entries.size(); ++i) {
|
||||
@ -12,8 +12,11 @@ Element Toggle::Render() {
|
||||
children.push_back(separator());
|
||||
|
||||
// Entry.
|
||||
auto style = i == selected ? highlight : dim;
|
||||
children.push_back(style(text(entries[i])));
|
||||
auto style = (selected != int(i))
|
||||
? normal_style
|
||||
: is_focused ? focused_style : selected_style;
|
||||
auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select;
|
||||
children.push_back(text(entries[i]) | style | focused);
|
||||
}
|
||||
return hbox(std::move(children));
|
||||
}
|
||||
@ -26,7 +29,7 @@ bool Toggle::OnEvent(Event event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (selected < entries.size() - 1 &&
|
||||
if (selected < int(entries.size()) - 1 &&
|
||||
(event == Event::ArrowRight || event == Event::Character('l'))) {
|
||||
selected++;
|
||||
on_change();
|
||||
|
@ -10,8 +10,8 @@ class Blink : public NodeDecorator {
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
Node::Render(screen);
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x, y).blink = true;
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ class Bold : public NodeDecorator {
|
||||
~Bold() override {}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x,y).bold = true;
|
||||
}
|
||||
}
|
||||
|
88
ftxui/src/ftxui/dom/border.cpp
Normal file
88
ftxui/src/ftxui/dom/border.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/dom/elements.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
static wchar_t charset[] = L"┌┐└┘─│┬┴┤├";
|
||||
|
||||
class Border : public Node {
|
||||
public:
|
||||
Border(Elements children) : Node(std::move(children)) {}
|
||||
~Border() override {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
Node::ComputeRequirement();
|
||||
requirement_ = children[0]->requirement();
|
||||
requirement_.min.x += 2;
|
||||
requirement_.min.y += 2;
|
||||
if (children.size() == 2) {
|
||||
requirement_.min.x =
|
||||
std::max(requirement_.min.x, children[1]->requirement().min.x + 2);
|
||||
}
|
||||
requirement_.selected_box.x_min++;
|
||||
requirement_.selected_box.x_max++;
|
||||
requirement_.selected_box.y_min++;
|
||||
requirement_.selected_box.y_max++;
|
||||
}
|
||||
|
||||
void SetBox(Box box) override {
|
||||
Node::SetBox(box);
|
||||
if (children.size() == 2) {
|
||||
Box title_box;
|
||||
title_box.x_min = box.x_min + 1;
|
||||
title_box.x_max = box.x_max - 1;
|
||||
title_box.y_min = box.y_min;
|
||||
title_box.y_max = box.y_min;
|
||||
children[1]->SetBox(title_box);
|
||||
}
|
||||
box.x_min++;
|
||||
box.x_max--;
|
||||
box.y_min++;
|
||||
box.y_max--;
|
||||
children[0]->SetBox(box);
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
// Draw content.
|
||||
children[0]->Render(screen);
|
||||
|
||||
// Draw the border.
|
||||
if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max)
|
||||
return;
|
||||
|
||||
screen.at(box_.x_min, box_.y_min) = charset[0];
|
||||
screen.at(box_.x_max, box_.y_min) = charset[1];
|
||||
screen.at(box_.x_min, box_.y_max) = charset[2];
|
||||
screen.at(box_.x_max, box_.y_max) = charset[3];
|
||||
for(float x = box_.x_min + 1; x<box_.x_max; ++x) {
|
||||
screen.at(x, box_.y_min) = charset[4];
|
||||
screen.at(x, box_.y_max) = charset[4];
|
||||
}
|
||||
for(float y = box_.y_min + 1; y<box_.y_max; ++y) {
|
||||
screen.at(box_.x_min, y) = charset[5];
|
||||
screen.at(box_.x_max,y) = charset[5];
|
||||
}
|
||||
|
||||
// Draw title.
|
||||
if (children.size() == 2)
|
||||
children[1]->Render(screen);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<Node> border(Element child) {
|
||||
return std::make_unique<Border>(unpack(std::move(child)));
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> window(Element title, Element content) {
|
||||
return std::make_unique<Border>(unpack(std::move(content), std::move(title)));
|
||||
}
|
||||
|
||||
Decorator boxed() {
|
||||
return [](Element child) {
|
||||
return border(std::move(child));
|
||||
};
|
||||
}
|
||||
|
||||
}; // namespace ftxui
|
@ -9,8 +9,8 @@ class BgColor : public NodeDecorator {
|
||||
: NodeDecorator(std::move(children)), color_(color) {}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x, y).background_color = color_;
|
||||
}
|
||||
}
|
||||
@ -27,8 +27,8 @@ class FgColor : public NodeDecorator {
|
||||
~FgColor() override {}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x, y).foreground_color = color_;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,11 @@ class DBox : public Node {
|
||||
child->ComputeRequirement();
|
||||
requirement_.min.x = std::max(requirement_.min.x, child->requirement().min.x);
|
||||
requirement_.min.y = std::max(requirement_.min.y, child->requirement().min.y);
|
||||
|
||||
if (requirement_.selection < child->requirement().selection) {
|
||||
requirement_.selection = child->requirement().selection;
|
||||
requirement_.selected_box = child->requirement().selected_box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@ class Dim : public NodeDecorator {
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
Node::Render(screen);
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x,y).dim = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,69 +1,116 @@
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/dom/elements.hpp"
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/util/autoreset.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
static wchar_t charset[] = L"┌┐└┘─│┬┴┤├";
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Frame : public Node {
|
||||
class Select : public Node {
|
||||
public:
|
||||
Frame(Elements children) : Node(std::move(children)) {}
|
||||
~Frame() override {}
|
||||
Select(std::vector<std::unique_ptr<Node>> children)
|
||||
: Node(std::move(children)) {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
Node::ComputeRequirement();
|
||||
requirement_ = children[0]->requirement();
|
||||
requirement_.min.x += 2;
|
||||
requirement_.min.y += 2;
|
||||
if (children.size() == 2) {
|
||||
requirement_.min.x =
|
||||
std::max(requirement_.min.x, children[1]->requirement().min.x + 2);
|
||||
auto& selected_box = requirement_.selected_box;
|
||||
selected_box.x_min = 0;
|
||||
selected_box.y_min = 0;
|
||||
selected_box.x_max = requirement_.min.x;
|
||||
selected_box.y_max = requirement_.min.y;
|
||||
requirement_.selection = Requirement::SELECTED;
|
||||
};
|
||||
|
||||
void SetBox(Box box) override {
|
||||
box_ = box;
|
||||
children[0]->SetBox(box);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<Node> select(Element child) {
|
||||
return std::make_unique<Select>(unpack(std::move(child)));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Focus : public Select {
|
||||
public:
|
||||
Focus(std::vector<std::unique_ptr<Node>> children)
|
||||
: Select(std::move(children)) {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
Select::ComputeRequirement();
|
||||
requirement_.selection = Requirement::FOCUSED;
|
||||
};
|
||||
};
|
||||
|
||||
std::unique_ptr<Node> focus(Element child) {
|
||||
return std::make_unique<Focus>(unpack(std::move(child)));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Frame : public Node {
|
||||
public:
|
||||
Frame(std::vector<std::unique_ptr<Node>> children)
|
||||
: Node(std::move(children)) {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
Node::ComputeRequirement();
|
||||
requirement_ = children[0]->requirement();
|
||||
}
|
||||
|
||||
void SetBox(Box box) override {
|
||||
Node::SetBox(box);
|
||||
if (children.size() == 2) {
|
||||
Box title_box;
|
||||
title_box.left = box.left + 1;
|
||||
title_box.right = box.right - 1;
|
||||
title_box.top = box.top;
|
||||
title_box.bottom = box.top;
|
||||
children[1]->SetBox(title_box);
|
||||
}
|
||||
box.left++;
|
||||
box.right--;
|
||||
box.top++;
|
||||
box.bottom--;
|
||||
children[0]->SetBox(box);
|
||||
|
||||
int external_dimx = box.x_max - box.x_min;
|
||||
int external_dimy = box.y_max - box.y_min;
|
||||
|
||||
int internal_dimx = std::max(requirement_.min.x, external_dimx);
|
||||
int internal_dimy = std::max(requirement_.min.y, external_dimy);
|
||||
|
||||
auto& selected_box = requirement_.selected_box;
|
||||
int focused_dimx = selected_box.x_max - selected_box.x_min;
|
||||
int focused_dimy = selected_box.y_max - selected_box.y_min;
|
||||
int dx = selected_box.x_min - external_dimx / 2 + focused_dimx / 2;
|
||||
int dy = selected_box.y_min - external_dimy / 2 + focused_dimy / 2;
|
||||
dx = std::max(0, std::min(internal_dimx - external_dimx - 1, dx));
|
||||
dy = std::max(0, std::min(internal_dimy - external_dimy - 1, dy));
|
||||
|
||||
Box children_box = box;
|
||||
children_box.x_min = box.x_min - dx;
|
||||
children_box.y_min = box.y_min - dy;
|
||||
children_box.x_max = box.x_min + internal_dimx - dx;
|
||||
children_box.y_max = box.y_min + internal_dimy - dy;
|
||||
children[0]->SetBox(children_box);
|
||||
|
||||
// int dx = box.x_max - box.x_min;
|
||||
// int dy = box.y_max - box.y_min;
|
||||
// int cdx = std::min(children[0].requirement().min.x
|
||||
|
||||
// Box children_box;
|
||||
// children_box.x_min =
|
||||
// if (box.x_max - box.x_min >= children[0].requirement().min.x && //
|
||||
|
||||
// box.y_max - box.y_min >= children[0].requirement().min.y) {
|
||||
// children_[0]->SetBox(box);
|
||||
// dx = 0;
|
||||
// dy = 0;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// Box children_box;
|
||||
// children_box.x_min = box.x_min;
|
||||
// children_box.y_min = box.x_min;
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
// Draw content.
|
||||
AutoReset<Box> stencil(&screen.stencil,
|
||||
Box::Intersection(box_, screen.stencil));
|
||||
children[0]->Render(screen);
|
||||
|
||||
// Draw the frame.
|
||||
if (box_.left >= box_.right || box_.top >= box_.bottom)
|
||||
return;
|
||||
|
||||
screen.at(box_.left, box_.top) = charset[0];
|
||||
screen.at(box_.right, box_.top) = charset[1];
|
||||
screen.at(box_.left, box_.bottom) = charset[2];
|
||||
screen.at(box_.right, box_.bottom) = charset[3];
|
||||
for(float x = box_.left + 1; x<box_.right; ++x) {
|
||||
screen.at(x, box_.top) = charset[4];
|
||||
screen.at(x, box_.bottom) = charset[4];
|
||||
}
|
||||
for(float y = box_.top + 1; y<box_.bottom; ++y) {
|
||||
screen.at(box_.left, y) = charset[5];
|
||||
screen.at(box_.right,y) = charset[5];
|
||||
}
|
||||
|
||||
// Draw title.
|
||||
if (children.size() == 2)
|
||||
children[1]->Render(screen);
|
||||
}
|
||||
};
|
||||
|
||||
@ -71,14 +118,4 @@ std::unique_ptr<Node> frame(Element child) {
|
||||
return std::make_unique<Frame>(unpack(std::move(child)));
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> window(Element title, Element content) {
|
||||
return std::make_unique<Frame>(unpack(std::move(content), std::move(title)));
|
||||
}
|
||||
|
||||
Decorator boxed() {
|
||||
return [](Element child) {
|
||||
return frame(std::move(child));
|
||||
};
|
||||
}
|
||||
|
||||
}; // namespace ftxui
|
||||
|
@ -18,14 +18,14 @@ class Gauge : public Node {
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
float y = box_.top;
|
||||
float limit = box_.left + progress_ * (box_.right - box_.left + 1);
|
||||
float y = box_.y_min;
|
||||
float limit = box_.x_min + progress_ * (box_.x_max - box_.x_min + 1);
|
||||
int limit_int = limit;
|
||||
int x = box_.left;
|
||||
int x = box_.x_min;
|
||||
while (x < limit_int)
|
||||
screen.at(x++, y) = charset[9];
|
||||
screen.at(x++, y) = charset[int(9*(limit-limit_int))];
|
||||
while (x <= box_.right)
|
||||
while (x <= box_.x_max)
|
||||
screen.at(x++, y) = charset[0];
|
||||
}
|
||||
private:
|
||||
|
@ -15,6 +15,12 @@ class HBox : public Node {
|
||||
requirement_.flex.y = 0;
|
||||
for (auto& child : children) {
|
||||
child->ComputeRequirement();
|
||||
if (requirement_.selection < child->requirement().selection) {
|
||||
requirement_.selection = child->requirement().selection;
|
||||
requirement_.selected_box = child->requirement().selected_box;
|
||||
requirement_.selected_box.x_min += requirement_.min.x;
|
||||
requirement_.selected_box.x_max += requirement_.min.x;
|
||||
}
|
||||
requirement_.min.x += child->requirement().min.x;
|
||||
requirement_.min.y =
|
||||
std::max(requirement_.min.y, child->requirement().min.y);
|
||||
@ -28,33 +34,33 @@ class HBox : public Node {
|
||||
for (auto& child : children)
|
||||
flex_sum += child->requirement().flex.x;
|
||||
|
||||
int space = box.right - box.left + 1;
|
||||
int space = box.x_max - box.x_min + 1;
|
||||
int extra_space = space - requirement_.min.x;
|
||||
|
||||
int remaining_flex = flex_sum;
|
||||
int remaining_extra_space = extra_space;
|
||||
|
||||
int x = box.left;
|
||||
int x = box.x_min;
|
||||
for (auto& child : children) {
|
||||
if (x > box.right)
|
||||
if (x > box.x_max)
|
||||
break;
|
||||
|
||||
Box child_box = box;
|
||||
child_box.left = x;
|
||||
child_box.x_min = x;
|
||||
|
||||
child_box.right = x + child->requirement().min.x - 1;
|
||||
child_box.x_max = x + child->requirement().min.x - 1;
|
||||
|
||||
if (child->requirement().flex.x && remaining_extra_space > 0) {
|
||||
int added_space = remaining_extra_space * child->requirement().flex.x /
|
||||
remaining_flex;
|
||||
remaining_extra_space -= added_space;
|
||||
remaining_flex -= child->requirement().flex.x;
|
||||
child_box.right += added_space;
|
||||
child_box.x_max += added_space;
|
||||
}
|
||||
child_box.right = std::min(child_box.right, box.right);
|
||||
child_box.x_max = std::min(child_box.x_max, box.x_max);
|
||||
|
||||
child->SetBox(child_box);
|
||||
x = child_box.right + 1;
|
||||
x = child_box.x_max + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -12,8 +12,8 @@ class Inverted : public NodeDecorator {
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
Node::Render(screen);
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x,y).inverted = true;
|
||||
}
|
||||
}
|
||||
|
@ -28,13 +28,14 @@ void Render(Screen& screen, Node* node) {
|
||||
node->ComputeRequirement();
|
||||
|
||||
Box box;
|
||||
box.left = 0;
|
||||
box.top = 0;
|
||||
box.right = screen.dimx() - 1;
|
||||
box.bottom = screen.dimy() - 1;
|
||||
box.x_min = 0;
|
||||
box.y_min = 0;
|
||||
box.x_max = screen.dimx() - 1;
|
||||
box.y_max = screen.dimy() - 1;
|
||||
|
||||
// Step 2: Assign a dimension to the element.
|
||||
node->SetBox(box);
|
||||
screen.stencil = box;
|
||||
|
||||
// Step 3: Draw the element.
|
||||
node->Render(screen);
|
||||
|
@ -14,8 +14,8 @@ class Separator : public Node {
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
bool is_column = (box_.right == box_.left);
|
||||
bool is_line = (box_.top == box_.bottom);
|
||||
bool is_column = (box_.x_max == box_.x_min);
|
||||
bool is_line = (box_.y_min == box_.y_max);
|
||||
|
||||
wchar_t c = U'+';
|
||||
if (is_line && !is_column)
|
||||
@ -23,8 +23,8 @@ class Separator : public Node {
|
||||
else
|
||||
c = U'│';
|
||||
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.at(x, y) = c;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ class Size : public Node {
|
||||
~Size() override {}
|
||||
void ComputeRequirement() override {
|
||||
Node::ComputeRequirement();
|
||||
requirement_ = children[0]->requirement();
|
||||
requirement_.min.x = width_;
|
||||
requirement_.min.y = height_;
|
||||
requirement_.flex.x = 0;
|
||||
|
@ -15,12 +15,12 @@ class Text : public Node {
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
int x = box_.left;
|
||||
int y = box_.top;
|
||||
if (y > box_.bottom)
|
||||
int x = box_.x_min;
|
||||
int y = box_.y_min;
|
||||
if (y > box_.y_max)
|
||||
return;
|
||||
for (wchar_t c : text_) {
|
||||
if (x > box_.right)
|
||||
if (x > box_.x_max)
|
||||
return;
|
||||
screen.at(x++, y) = c;
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ class Underlined : public NodeDecorator {
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
Node::Render(screen);
|
||||
for (int y = box_.top; y <= box_.bottom; ++y) {
|
||||
for (int x = box_.left; x <= box_.right; ++x) {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x, y).underlined = true;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,12 @@ class VBox : public Node {
|
||||
requirement_.flex.y = 1;
|
||||
for (auto& child : children) {
|
||||
child->ComputeRequirement();
|
||||
if (requirement_.selection < child->requirement().selection) {
|
||||
requirement_.selection = child->requirement().selection;
|
||||
requirement_.selected_box = child->requirement().selected_box;
|
||||
requirement_.selected_box.y_min += requirement_.min.y;
|
||||
requirement_.selected_box.y_max += requirement_.min.y;
|
||||
}
|
||||
requirement_.min.y += child->requirement().min.y;
|
||||
requirement_.min.x =
|
||||
std::max(requirement_.min.x, child->requirement().min.x);
|
||||
@ -28,33 +34,33 @@ class VBox : public Node {
|
||||
for (auto& child : children)
|
||||
flex_sum += child->requirement().flex.y;
|
||||
|
||||
int space = box.bottom - box.top + 1;
|
||||
int space = box.y_max - box.y_min + 1;
|
||||
int extra_space = space - requirement_.min.y;
|
||||
|
||||
int remaining_flex = flex_sum;
|
||||
int remaining_extra_space = extra_space;
|
||||
|
||||
int y = box.top;
|
||||
int y = box.y_min;
|
||||
for (auto& child : children) {
|
||||
if (y > box.bottom)
|
||||
if (y > box.y_max)
|
||||
break;
|
||||
|
||||
Box child_box = box;
|
||||
child_box.top = y;
|
||||
child_box.y_min = y;
|
||||
|
||||
child_box.bottom = y + child->requirement().min.y - 1;
|
||||
child_box.y_max = y + child->requirement().min.y - 1;
|
||||
|
||||
if (child->requirement().flex.y && remaining_extra_space > 0) {
|
||||
int added_space = remaining_extra_space * child->requirement().flex.y /
|
||||
remaining_flex;
|
||||
remaining_extra_space -= added_space;
|
||||
remaining_flex -= child->requirement().flex.y;
|
||||
child_box.bottom += added_space;
|
||||
child_box.y_max += added_space;
|
||||
}
|
||||
child_box.bottom = std::min(child_box.bottom, box.bottom);
|
||||
child_box.y_max = std::min(child_box.y_max, box.y_max);
|
||||
|
||||
child->SetBox(child_box);
|
||||
y = child_box.bottom + 1;
|
||||
y = child_box.y_max + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
14
ftxui/src/ftxui/screen/box.cpp
Normal file
14
ftxui/src/ftxui/screen/box.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "ftxui/screen/box.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace ftxui {
|
||||
// static
|
||||
Box Box::Intersection(Box a, Box b) {
|
||||
return Box{
|
||||
std::max(a.x_min, b.x_min),
|
||||
std::min(a.x_max, b.x_max),
|
||||
std::max(a.y_min, b.y_min),
|
||||
std::min(a.y_max, b.y_max),
|
||||
};
|
||||
}
|
||||
} // namespace ftxui
|
@ -7,6 +7,7 @@
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
namespace {
|
||||
static const wchar_t* BOLD_SET = L"\e[1m";
|
||||
static const wchar_t* BOLD_RESET = L"\e[22m"; // Can't use 21 here.
|
||||
|
||||
@ -26,8 +27,20 @@ static const char* MOVE_LEFT = "\r";
|
||||
static const char* MOVE_UP = "\e[1A";
|
||||
static const char* CLEAR_LINE = "\e[2K";
|
||||
|
||||
bool In(const Box& stencil, int x, int y) {
|
||||
return stencil.x_min <= x && x <= stencil.x_max && //
|
||||
stencil.y_min <= y && y <= stencil.y_max;
|
||||
}
|
||||
|
||||
Pixel dev_null_pixel;
|
||||
|
||||
} // namespace
|
||||
|
||||
Screen::Screen(size_t dimx, size_t dimy)
|
||||
: dimx_(dimx), dimy_(dimy), pixels_(dimy, std::vector<Pixel>(dimx)) {}
|
||||
: stencil({0, int(dimx) - 1, 0, int(dimy) - 1}),
|
||||
dimx_(dimx),
|
||||
dimy_(dimy),
|
||||
pixels_(dimy, std::vector<Pixel>(dimx)) {}
|
||||
|
||||
void UpdatePixelStyle(std::wstringstream& ss, Pixel& previous, Pixel& next) {
|
||||
if (next.bold != previous.bold)
|
||||
@ -76,11 +89,11 @@ std::string Screen::ToString() {
|
||||
}
|
||||
|
||||
wchar_t& Screen::at(size_t x, size_t y) {
|
||||
return pixels_[y][x].character;
|
||||
return PixelAt(x,y).character;
|
||||
}
|
||||
|
||||
Pixel& Screen::PixelAt(size_t x, size_t y) {
|
||||
return pixels_[y][x];
|
||||
return In(stencil, x, y) ? pixels_[y][x] : dev_null_pixel;
|
||||
}
|
||||
|
||||
// static
|
||||
|
62
tutorial.md
62
tutorial.md
@ -5,7 +5,7 @@
|
||||
+ [Examples](#examples)
|
||||
* [Widget.](#widget)
|
||||
+ [text](#text)
|
||||
+ [frame](#frame)
|
||||
+ [border](#border)
|
||||
+ [separator](#separator)
|
||||
+ [gauge](#gauge)
|
||||
* [Decorator](#decorator)
|
||||
@ -27,21 +27,11 @@ All the dom element are declared in one header:
|
||||
It declares the following set of elements:
|
||||
|
||||
~~~cpp
|
||||
// --- Layout ----
|
||||
Element vbox(Elements);
|
||||
Element hbox(Elements);
|
||||
Element dbox(Elements);
|
||||
|
||||
// -- Flexibility --
|
||||
Element filler();
|
||||
Element flex(Element);
|
||||
Decorator size(size_t width, size_t height);
|
||||
|
||||
// --- Widget --
|
||||
// --- Widget ---
|
||||
Element text(std::wstring text);
|
||||
Element separator();
|
||||
Element gauge(float ratio);
|
||||
Element frame(Element);
|
||||
Element border(Element);
|
||||
Element window(Element title, Element content);
|
||||
Element spinner(int charset_index, size_t image_index);
|
||||
|
||||
@ -51,19 +41,37 @@ Element dim(Element);
|
||||
Element inverted(Element);
|
||||
Element underlined(Element);
|
||||
Element blink(Element);
|
||||
|
||||
Decorator color(Color);
|
||||
Decorator bgcolor(Color);
|
||||
Element color(Color, Element);
|
||||
Element bgcolor(Color, Element);
|
||||
|
||||
// --- Util ---
|
||||
// --- Layout ---
|
||||
// Horizontal, Vertical or stacked set of elements.
|
||||
Element vbox(Elements);
|
||||
Element hbox(Elements);
|
||||
Element dbox(Elements);
|
||||
|
||||
// -- Flexibility ---
|
||||
// Define how to share the remaining space when not all of it is used inside a
|
||||
// container.
|
||||
Element filler();
|
||||
Element flex(Element);
|
||||
Decorator size(size_t width, size_t height);
|
||||
|
||||
// --- 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 focus(Element);
|
||||
Element select(Element);
|
||||
|
||||
// --- Util --------------------------------------------------------------------
|
||||
Element hcenter(Element);
|
||||
Element vcenter(Element);
|
||||
Element center(Element);
|
||||
Element align_right(Element);
|
||||
|
||||
// --- Util ---
|
||||
Element nothing(Element element);
|
||||
~~~
|
||||
|
||||
@ -98,9 +106,9 @@ container.
|
||||
#### Examples
|
||||
~~~cpp
|
||||
hbox(
|
||||
text(L"left") | frame ,
|
||||
text(L"middle") | frame | flex,
|
||||
text(L"right") | frame
|
||||
text(L"left") | border ,
|
||||
text(L"middle") | border | flex,
|
||||
text(L"right") | border
|
||||
);
|
||||
~~~
|
||||
~~~bash
|
||||
@ -111,9 +119,9 @@ container.
|
||||
|
||||
~~~cpp
|
||||
hbox(
|
||||
text(L"left") | frame ,
|
||||
text(L"middle") | frame | flex,
|
||||
text(L"right") | frame | flex
|
||||
text(L"left") | border ,
|
||||
text(L"middle") | border | flex,
|
||||
text(L"right") | border | flex
|
||||
);
|
||||
~~~
|
||||
~~~bash
|
||||
@ -134,10 +142,10 @@ The most simple widget. It display a text.
|
||||
I am a piece of text.
|
||||
~~~
|
||||
|
||||
#### frame
|
||||
#### border
|
||||
Add a border arround an element
|
||||
~~~cpp
|
||||
frame(text(L"The element"))
|
||||
border(text(L"The element"))
|
||||
~~~
|
||||
|
||||
~~~bash
|
||||
@ -152,7 +160,7 @@ Display a vertical or horizontal line to visually split the content of a
|
||||
container in two.
|
||||
|
||||
~~~cpp
|
||||
frame(hbox(
|
||||
border(hbox(
|
||||
vbox(
|
||||
text(L"left top"),
|
||||
text(L"left bottom")
|
||||
@ -176,7 +184,7 @@ frame(hbox(
|
||||
|
||||
A gauge. It can be used to represent a progress bar.
|
||||
~~~c+
|
||||
frame(gauge(0.5))
|
||||
border(gauge(0.5))
|
||||
~~~
|
||||
|
||||
~~~bash
|
||||
|
Loading…
Reference in New Issue
Block a user