Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add index to EntryState #933

Merged
merged 3 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ current (development)
- Bugfix: Fix cursor position in when in the last column. See #831.
- Bugfix: Fix `ResizeableSplit` keyboard navigation. Fixed by #842.
- Bugfix: Fix `Menu` focus. See #841
- Feature: Add `ComponentBase::Index()`. This allows to get the index of a
component in its parent. See #932
- Feature: Add `EntryState::index`. This allows to get the index of a menu entry.
See #932

### Dom
- Feature: Add `hscroll_indicator`. It display an horizontal indicator
Expand Down
1 change: 1 addition & 0 deletions include/ftxui/component/component_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class ComponentBase {
ComponentBase* Parent() const;
Component& ChildAt(size_t i);
size_t ChildCount() const;
int Index() const;
void Add(Component children);
void Detach();
void DetachAllChildren();
Expand Down
1 change: 1 addition & 0 deletions include/ftxui/component/component_options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct EntryState {
bool state; ///< The state of the button/checkbox/radiobox
bool active; ///< Whether the entry is the active one.
bool focused; ///< Whether the entry is one focused by the user.
int index; ///< Index of the entry when applicable or -1.
};

struct UnderlineOption {
Expand Down
7 changes: 2 additions & 5 deletions src/ftxui/component/button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,8 @@ class ButtonBase : public ComponentBase, public ButtonOption {
}

auto focus_management = focused ? focus : active ? select : nothing;
const EntryState state = {
*label,
false,
active,
focused_or_hover,
const EntryState state{
*label, false, active, focused_or_hover, Index(),
};

auto element = (transform ? transform : DefaultTransform) //
Expand Down
5 changes: 1 addition & 4 deletions src/ftxui/component/checkbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ class CheckboxBase : public ComponentBase, public CheckboxOption {
const bool is_active = Active();
auto focus_management = is_focused ? focus : is_active ? select : nothing;
auto entry_state = EntryState{
*label,
*checked,
is_active,
is_focused || hovered_,
*label, *checked, is_active, is_focused || hovered_, -1,
};
auto element = (transform ? transform : CheckboxOption::Simple().transform)(
entry_state);
Expand Down
16 changes: 16 additions & 0 deletions src/ftxui/component/component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ size_t ComponentBase::ChildCount() const {
return children_.size();
}

/// @brief Return index of the component in its parent. -1 if no parent.
/// @ingroup component
int ComponentBase::Index() const {
if (parent_ == nullptr) {
return -1;
}
int index = 0;
for (const Component& child : parent_->children_) {
if (child.get() == this) {
return index;
}
index++;
}
return -1; // Not reached.
}

/// @brief Add a child.
/// @@param child The child to be attached.
/// @ingroup component
Expand Down
12 changes: 3 additions & 9 deletions src/ftxui/component/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,7 @@ class MenuBase : public ComponentBase, public MenuOption {
const bool is_selected = (selected() == i);

const EntryState state = {
entries[i],
false,
is_selected,
is_focused,
entries[i], false, is_selected, is_focused, i,
};

auto focus_management = (selected_focus_ != i) ? nothing
Expand Down Expand Up @@ -625,11 +622,8 @@ Component MenuEntry(MenuEntryOption option) {
const bool focused = Focused();
UpdateAnimationTarget();

const EntryState state = {
label(),
false,
hovered_,
focused,
const EntryState state{
label(), false, hovered_, focused, Index(),
};

const Element element =
Expand Down
45 changes: 45 additions & 0 deletions src/ftxui/component/menu_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,5 +226,50 @@ TEST(MenuTest, AnimationsVertical) {
}
}

TEST(MenuTest, EntryIndex) {
int selected = 0;
std::vector<std::string> entries = {"0", "1", "2"};

auto option = MenuOption::Vertical();
option.entries = &entries;
option.selected = &selected;
option.entries_option.transform = [&](const EntryState& state) {
int curidx = std::stoi(state.label);
EXPECT_EQ(state.index, curidx);
return text(state.label);
};
auto menu = Menu(option);
menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::Return);
entries.resize(2);
(void)menu->Render();
}

TEST(MenuTest, MenuEntryIndex) {
int selected = 0;

MenuEntryOption option;
option.transform = [&](const EntryState& state) {
int curidx = std::stoi(state.label);
EXPECT_EQ(state.index, curidx);
return text(state.label);
};
auto menu = Container::Vertical(
{
MenuEntry("0", option),
MenuEntry("1", option),
MenuEntry("2", option),
},
&selected);

menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::ArrowDown);
menu->OnEvent(Event::Return);
for (int index = 0; index < menu->ChildCount(); index++) {
EXPECT_EQ(menu->ChildAt(index)->Index(), index);
}
}

} // namespace ftxui
// NOLINTEND
5 changes: 1 addition & 4 deletions src/ftxui/component/radiobox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ class RadioboxBase : public ComponentBase, public RadioboxOption {
: is_menu_focused ? focus
: select;
auto state = EntryState{
entries[i],
selected() == i,
is_selected,
is_focused,
entries[i], selected() == i, is_selected, is_focused, i,
};
auto element =
(transform ? transform : RadioboxOption::Simple().transform)(state);
Expand Down
Loading