mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-06-27 02:01:12 +08:00
Add full customization.
This commit is contained in:
parent
00fbdd98d4
commit
60ba15ac07
@ -11,6 +11,7 @@ example(collapsible)
|
||||
example(composition)
|
||||
example(custom_loop)
|
||||
example(dropdown)
|
||||
example(dropdown_custom)
|
||||
example(flexbox_gallery)
|
||||
example(focus)
|
||||
example(focus_cursor)
|
||||
|
69
examples/component/dropdown_custom.cpp
Normal file
69
examples/component/dropdown_custom.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#include <string> // for basic_string, string, allocator
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/captured_mouse.hpp" // for ftxui
|
||||
#include "ftxui/component/component.hpp" // for Dropdown, Horizontal, Vertical
|
||||
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
|
||||
|
||||
int main() {
|
||||
using namespace ftxui;
|
||||
|
||||
std::vector<std::string> entries = {
|
||||
"tribute", "clearance", "ally", "bend", "electronics",
|
||||
"module", "era", "cultural", "sniff", "nationalism",
|
||||
"negotiation", "deliver", "figure", "east", "tribute",
|
||||
"clearance", "ally", "bend", "electronics", "module",
|
||||
"era", "cultural", "sniff", "nationalism", "negotiation",
|
||||
"deliver", "figure", "east", "tribute", "clearance",
|
||||
"ally", "bend", "electronics", "module", "era",
|
||||
"cultural", "sniff", "nationalism", "negotiation", "deliver",
|
||||
"figure", "east",
|
||||
};
|
||||
|
||||
auto dropdown_1 = Dropdown({
|
||||
.radiobox = {.entries = &entries},
|
||||
.transform =
|
||||
[](bool open, Element checkbox, Element radiobox) {
|
||||
if (open) {
|
||||
return vbox({
|
||||
checkbox | inverted,
|
||||
radiobox | vscroll_indicator | frame |
|
||||
size(HEIGHT, LESS_THAN, 10),
|
||||
filler(),
|
||||
});
|
||||
}
|
||||
return vbox({
|
||||
checkbox,
|
||||
filler(),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
auto dropdown_2 = Dropdown({
|
||||
.radiobox = {.entries = &entries},
|
||||
.transform =
|
||||
[](bool open, Element checkbox, Element radiobox) {
|
||||
if (open) {
|
||||
return vbox({
|
||||
checkbox | inverted,
|
||||
radiobox | vscroll_indicator | frame |
|
||||
size(HEIGHT, LESS_THAN, 10) | bgcolor(Color::Blue),
|
||||
filler(),
|
||||
});
|
||||
}
|
||||
return vbox({
|
||||
checkbox | bgcolor(Color::Blue),
|
||||
filler(),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
auto screen = ScreenInteractive::FitComponent();
|
||||
screen.Loop(Container::Horizontal({
|
||||
dropdown_1,
|
||||
dropdown_2,
|
||||
}));
|
||||
}
|
@ -74,9 +74,8 @@ Component Radiobox(ConstStringListRef entries,
|
||||
int* selected_,
|
||||
RadioboxOption options = {});
|
||||
|
||||
Component Dropdown(ConstStringListRef entries,
|
||||
int* selected,
|
||||
DropdownOption options = {});
|
||||
Component Dropdown(ConstStringListRef entries, int* selected);
|
||||
Component Dropdown(DropdownOption options);
|
||||
|
||||
Component Toggle(ConstStringListRef entries, int* selected);
|
||||
|
||||
|
@ -148,15 +148,6 @@ struct CheckboxOption {
|
||||
std::function<void()> on_change = [] {};
|
||||
};
|
||||
|
||||
/// @brief Option for the Dropdown component.
|
||||
/// @ingroup component
|
||||
struct DropdownOption {
|
||||
bool border = true;
|
||||
|
||||
// Observer:
|
||||
/// Called when the user change the state.
|
||||
std::function<void()> on_change = [] {};
|
||||
};
|
||||
|
||||
/// @brief Used to define style for the Input component.
|
||||
struct InputState {
|
||||
@ -273,6 +264,17 @@ struct WindowOptions {
|
||||
std::function<Element(const WindowRenderState&)> render;
|
||||
};
|
||||
|
||||
/// @brief Option for the Dropdown component.
|
||||
/// @ingroup component
|
||||
/// A dropdown menu is a checkbox opening/closing a radiobox.
|
||||
struct DropdownOption {
|
||||
Ref<bool> open = false;
|
||||
CheckboxOption checkbox;
|
||||
RadioboxOption radiobox;
|
||||
std::function<Element(bool open, Element checkbox, Element radiobox)>
|
||||
transform;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_OPTIONS_HPP */
|
||||
|
@ -19,100 +19,102 @@ namespace ftxui {
|
||||
/// @ingroup component
|
||||
/// @param entries The list of entries to display.
|
||||
/// @param selected The index of the selected entry.
|
||||
Component Dropdown(ConstStringListRef entries, int* selected, DropdownOption option) {
|
||||
class Impl : public ComponentBase {
|
||||
Component Dropdown(ConstStringListRef entries, int* selected) {
|
||||
DropdownOption option;
|
||||
option.radiobox.entries = entries;
|
||||
option.radiobox.selected = selected;
|
||||
return Dropdown(option);
|
||||
}
|
||||
|
||||
/// @brief A dropdown menu.
|
||||
/// @ingroup component
|
||||
/// @param option The options for the dropdown.
|
||||
Component Dropdown(DropdownOption option) {
|
||||
class Impl : public ComponentBase, public DropdownOption {
|
||||
public:
|
||||
Impl(ConstStringListRef entries, int* selected, DropdownOption dropDownOption)
|
||||
: entries_(entries), selected_(selected) {
|
||||
CheckboxOption option;
|
||||
option.transform = [](const EntryState& s) {
|
||||
auto prefix = text(s.state ? "↓ " : "→ "); // NOLINT
|
||||
auto t = text(s.label);
|
||||
if (s.active) {
|
||||
t |= bold;
|
||||
}
|
||||
if (s.focused) {
|
||||
t |= inverted;
|
||||
}
|
||||
return hbox({prefix, t});
|
||||
};
|
||||
checkbox_ = Checkbox(&title_, &show_, option);
|
||||
|
||||
RadioboxOption radioboxOption;
|
||||
radioboxOption.on_change = dropDownOption.on_change;
|
||||
|
||||
radiobox_ = Radiobox(entries_, selected_, radioboxOption);
|
||||
Impl(DropdownOption option) : DropdownOption(std::move(option)) {
|
||||
FillDefault();
|
||||
checkbox_ = Checkbox(checkbox);
|
||||
radiobox_ = Radiobox(radiobox);
|
||||
|
||||
Add(Container::Vertical({
|
||||
checkbox_,
|
||||
Maybe(radiobox_, &show_),
|
||||
Maybe(radiobox_, checkbox.checked),
|
||||
}));
|
||||
|
||||
border_ = dropDownOption.border;
|
||||
}
|
||||
|
||||
Element Render() override {
|
||||
*selected_ = util::clamp(*selected_, 0, int(entries_.size()) - 1);
|
||||
title_ = entries_[static_cast<size_t>(*selected_)];
|
||||
if (show_) {
|
||||
const int max_height = 12;
|
||||
auto element = vbox({
|
||||
checkbox_->Render(),
|
||||
separator(),
|
||||
radiobox_->Render() | vscroll_indicator | frame |
|
||||
size(HEIGHT, LESS_THAN, max_height),
|
||||
});
|
||||
|
||||
if (border_)
|
||||
{
|
||||
element |= border;
|
||||
}
|
||||
radiobox.selected =
|
||||
util::clamp(radiobox.selected(), 0, int(radiobox.entries.size()) - 1);
|
||||
checkbox.label =
|
||||
radiobox.entries[static_cast<size_t>(radiobox.selected())];
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
auto element = checkbox_->Render();
|
||||
|
||||
if (border_)
|
||||
{
|
||||
element |= border;
|
||||
}
|
||||
|
||||
return vbox({
|
||||
element,
|
||||
filler(),
|
||||
});
|
||||
return transform(*open_, checkbox_->Render(), radiobox_->Render());
|
||||
}
|
||||
|
||||
// Switch focus in between the checkbox and the radiobox when selecting it.
|
||||
bool OnEvent(ftxui::Event event) override {
|
||||
const bool show_old = show_;
|
||||
const int selected_old = *selected_;
|
||||
const bool show_old = open_();
|
||||
const int selected_old = selected_();
|
||||
const bool handled = ComponentBase::OnEvent(event);
|
||||
|
||||
if (!show_old && show_) {
|
||||
if (!show_old && open_()) {
|
||||
radiobox_->TakeFocus();
|
||||
}
|
||||
|
||||
if (selected_old != *selected_) {
|
||||
if (selected_old != selected_()) {
|
||||
checkbox_->TakeFocus();
|
||||
show_ = false;
|
||||
open_ = false;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
void FillDefault() {
|
||||
open_ = std::move(checkbox.checked);
|
||||
selected_ = std::move(radiobox.selected);
|
||||
checkbox.checked = &*open_;
|
||||
radiobox.selected = &*selected_;
|
||||
|
||||
if (!checkbox.transform) {
|
||||
checkbox.transform = [](const EntryState& s) {
|
||||
auto prefix = text(s.state ? "↓ " : "→ "); // NOLINT
|
||||
auto t = text(s.label);
|
||||
if (s.active) {
|
||||
t |= bold;
|
||||
}
|
||||
if (s.focused) {
|
||||
t |= inverted;
|
||||
}
|
||||
return hbox({prefix, t});
|
||||
};
|
||||
}
|
||||
|
||||
if (!transform) {
|
||||
transform = [](bool open, Element checkbox, Element radiobox) {
|
||||
if (open) {
|
||||
const int max_height = 12;
|
||||
return vbox({
|
||||
checkbox,
|
||||
separator(),
|
||||
radiobox | vscroll_indicator | frame |
|
||||
size(HEIGHT, LESS_THAN, max_height),
|
||||
}) |
|
||||
border;
|
||||
}
|
||||
return vbox({checkbox, filler()}) | border;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ConstStringListRef entries_;
|
||||
bool show_ = false;
|
||||
bool border_ = true;
|
||||
int* selected_;
|
||||
std::string title_;
|
||||
Ref<bool> open_;
|
||||
Ref<int> selected_;
|
||||
Component checkbox_;
|
||||
Component radiobox_;
|
||||
};
|
||||
|
||||
return Make<Impl>(entries, selected, option);
|
||||
return Make<Impl>(option);
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
Loading…
Reference in New Issue
Block a user