#include // for size_t #include // for find_if, max #include // for assert #include // for begin, end #include // for move #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface #include "ftxui/component/component.hpp" #include "ftxui/component/component_base.hpp" // for ComponentBase, Component #include "ftxui/component/event.hpp" // for Event #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/dom/elements.hpp" // for text, Element namespace ftxui { namespace { class CaptureMouseImpl : public CapturedMouseInterface {}; } // namespace ComponentBase::~ComponentBase() { DetachAllChildren(); } /// @brief Return the parent ComponentBase, or nul if any. /// @see Detach /// @see Parent /// @ingroup component ComponentBase* ComponentBase::Parent() const { return parent_; } /// @brief Access the child at index `i`. /// @ingroup component Component& ComponentBase::ChildAt(size_t i) { assert(i < ChildCount()); return children_[i]; } /// @brief Returns the number of children. /// @ingroup component size_t ComponentBase::ChildCount() const { return children_.size(); } /// @brief Add a child. /// @@param child The child to be attached. /// @ingroup component void ComponentBase::Add(Component child) { child->Detach(); child->parent_ = this; children_.push_back(std::move(child)); } /// @brief Detach this child from its parent. /// @see Detach /// @see Parent /// @ingroup component void ComponentBase::Detach() { if (!parent_) return; auto it = std::find_if(std::begin(parent_->children_), // std::end(parent_->children_), // [this](const Component& that) { // return this == that.get(); }); parent_->children_.erase(it); parent_ = nullptr; } /// @brief Remove all children. /// @ingroup component void ComponentBase::DetachAllChildren() { while (!children_.empty()) children_[0]->Detach(); } /// @brief Draw the component. /// Build a ftxui::Element to be drawn on the ftxi::Screen representing this /// ftxui::ComponentBase. /// @ingroup component Element ComponentBase::Render() { if (children_.size() == 1) return children_.front()->Render(); return text(L"Not implemented component"); } /// @brief Called in response to an event. /// @param event The event. /// @return True when the event has been handled. /// The default implementation called OnEvent on every child until one return /// true. If none returns true, return false. /// @ingroup component bool ComponentBase::OnEvent(Event event) { for (Component& child : children_) { if (child->OnEvent(event)) return true; } return false; } /// @brief Return the currently Active child. /// @return the currently Active child. /// @ingroup component Component ComponentBase::ActiveChild() { return children_.empty() ? nullptr : children_.front(); } /// @brief Returns if the element if the currently active child of its parent. /// @ingroup component bool ComponentBase::Active() const { return !parent_ || parent_->ActiveChild().get() == this; } /// @brief Returns if the elements if focused by the user. /// True when the ComponentBase is focused by the user. An element is Focused /// when it is with all its ancestors the ActiveChild() of their parents. /// @ingroup component bool ComponentBase::Focused() const { auto current = this; while (current && current->Active()) { current = current->parent_; } return !current; } /// @brief Make the |child| to be the "active" one. /// @param child the child to become active. /// @ingroup component void ComponentBase::SetActiveChild(ComponentBase*) {} /// @brief Make the |child| to be the "active" one. /// @param child the child to become active. /// @ingroup component void ComponentBase::SetActiveChild(Component child) { SetActiveChild(child.get()); } /// @brief Configure all the ancestors to give focus to this component. /// @ingroup component void ComponentBase::TakeFocus() { ComponentBase* child = this; while (ComponentBase* parent = child->parent_) { parent->SetActiveChild(child); child = parent; } } /// @brief Take the CapturedMouse if available. There is only one component of /// them. It represents a component taking priority over others. /// @param event /// @ingroup component CapturedMouse ComponentBase::CaptureMouse(const Event& event) { if (event.screen_) return event.screen_->CaptureMouse(); return std::make_unique(); } } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in // the LICENSE file.